Browse Source

Merge pull request #19 from jld3103/feature/notifications-push-proxy

Implement notifications API and push proxy library
pull/23/head
jld3103 3 years ago committed by GitHub
parent
commit
114d6427c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      .github/workflows/dart.yml
  2. 3
      .gitmodules
  3. 5
      .idea/nextcloud-harbour.iml
  4. 1
      .idea/vcs.xml
  5. 1
      external/nextcloud-notifications
  6. 16
      packages/nextcloud/doc/notifications/AdminNotification.md
  7. 318
      packages/nextcloud/doc/notifications/DefaultApi.md
  8. 15
      packages/nextcloud/doc/notifications/EmptyResponse.md
  9. 16
      packages/nextcloud/doc/notifications/EmptyResponseOcs.md
  10. 15
      packages/nextcloud/doc/notifications/GetNotificationResponse.md
  11. 16
      packages/nextcloud/doc/notifications/GetNotificationResponseOcs.md
  12. 15
      packages/nextcloud/doc/notifications/ListNotificationsResponse.md
  13. 16
      packages/nextcloud/doc/notifications/ListNotificationsResponseOcs.md
  14. 29
      packages/nextcloud/doc/notifications/Notification.md
  15. 19
      packages/nextcloud/doc/notifications/PushNotificationDecryptedSubject.md
  16. 17
      packages/nextcloud/doc/notifications/PushServerDevice.md
  17. 15
      packages/nextcloud/doc/notifications/PushServerRegistrationResponse.md
  18. 16
      packages/nextcloud/doc/notifications/PushServerRegistrationResponseOcs.md
  19. 17
      packages/nextcloud/doc/notifications/PushServerSubscription.md
  20. 5
      packages/nextcloud/lib/nextcloud.dart
  21. 9
      packages/nextcloud/lib/src/client.dart
  22. 16
      packages/nextcloud/lib/src/clients/custom/webdav/client.dart
  23. 1
      packages/nextcloud/lib/src/clients/custom/webdav/webdav.dart
  24. 39
      packages/nextcloud/lib/src/clients/generated/notifications/api.dart
  25. 364
      packages/nextcloud/lib/src/clients/generated/notifications/api/default_api.dart
  26. 329
      packages/nextcloud/lib/src/clients/generated/notifications/api_client.dart
  27. 139
      packages/nextcloud/lib/src/clients/generated/notifications/model/admin_notification.dart
  28. 124
      packages/nextcloud/lib/src/clients/generated/notifications/model/empty_response.dart
  29. 125
      packages/nextcloud/lib/src/clients/generated/notifications/model/empty_response_ocs.dart
  30. 124
      packages/nextcloud/lib/src/clients/generated/notifications/model/get_notification_response.dart
  31. 133
      packages/nextcloud/lib/src/clients/generated/notifications/model/get_notification_response_ocs.dart
  32. 124
      packages/nextcloud/lib/src/clients/generated/notifications/model/list_notifications_response.dart
  33. 125
      packages/nextcloud/lib/src/clients/generated/notifications/model/list_notifications_response_ocs.dart
  34. 316
      packages/nextcloud/lib/src/clients/generated/notifications/model/notification.dart
  35. 187
      packages/nextcloud/lib/src/clients/generated/notifications/model/push_notification_decrypted_subject.dart
  36. 158
      packages/nextcloud/lib/src/clients/generated/notifications/model/push_server_device.dart
  37. 125
      packages/nextcloud/lib/src/clients/generated/notifications/model/push_server_registration_response.dart
  38. 133
      packages/nextcloud/lib/src/clients/generated/notifications/model/push_server_registration_response_ocs.dart
  39. 158
      packages/nextcloud/lib/src/clients/generated/notifications/model/push_server_subscription.dart
  40. 98
      packages/nextcloud/lib/src/clients/notifications.dart
  41. 12
      packages/nextcloud/lib/src/http_client_response_extension.dart
  42. 5
      packages/nextcloud/pubspec.yaml
  43. 48
      packages/nextcloud/test/helper.dart
  44. 220
      packages/nextcloud/test/notifications_test.dart
  45. 12
      packages/nextcloud/test/webdav_test.dart
  46. 10
      packages/nextcloud_push_proxy/.gitignore
  47. 12
      packages/nextcloud_push_proxy/LICENSE
  48. 5
      packages/nextcloud_push_proxy/analysis_options.yaml
  49. 143
      packages/nextcloud_push_proxy/lib/nextcloud_push_proxy.dart
  50. 7
      packages/nextcloud_push_proxy/mono_pkg.yaml
  51. 15
      packages/nextcloud_push_proxy/pubspec.yaml
  52. 389
      specs/notifications.json
  53. 235
      specs/templates/notifications.json
  54. 2
      tool/generate-nextcloud.sh

30
.github/workflows/dart.yml

@ -35,16 +35,16 @@ jobs:
- name: mono_repo self validate
run: dart pub global run mono_repo generate --validate
job_002:
name: "analyze; PKGS: packages/file_icons, packages/harbour, packages/nextcloud, packages/settings, packages/sort_box, packages/spec_templates; `dart format --output=none --set-exit-if-changed --line-length 120 .`"
name: "analyze; PKGS: packages/file_icons, packages/harbour, packages/nextcloud, packages/nextcloud_push_proxy, packages/settings, packages/sort_box, packages/spec_templates; `dart format --output=none --set-exit-if-changed --line-length 120 .`"
runs-on: ubuntu-latest
steps:
- name: Cache Pub hosted dependencies
uses: actions/cache@4504faf7e9bcf8f3ed0bc863c4e1d21499ab8ef8
with:
path: "~/.pub-cache/hosted"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/file_icons-packages/harbour-packages/nextcloud-packages/settings-packages/sort_box-packages/spec_templates;commands:format"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/file_icons-packages/harbour-packages/nextcloud-packages/nextcloud_push_proxy-packages/settings-packages/sort_box-packages/spec_templates;commands:format"
restore-keys: |
os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/file_icons-packages/harbour-packages/nextcloud-packages/settings-packages/sort_box-packages/spec_templates
os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/file_icons-packages/harbour-packages/nextcloud-packages/nextcloud_push_proxy-packages/settings-packages/sort_box-packages/spec_templates
os:ubuntu-latest;pub-cache-hosted;sdk:stable
os:ubuntu-latest;pub-cache-hosted
os:ubuntu-latest
@ -80,6 +80,15 @@ jobs:
if: "always() && steps.packages_nextcloud_pub_upgrade.conclusion == 'success'"
working-directory: packages/nextcloud
run: "dart format --output=none --set-exit-if-changed --line-length 120 ."
- id: packages_nextcloud_push_proxy_pub_upgrade
name: packages/nextcloud_push_proxy; flutter pub pub upgrade
if: "always() && steps.checkout.conclusion == 'success'"
working-directory: packages/nextcloud_push_proxy
run: flutter pub pub upgrade
- name: "packages/nextcloud_push_proxy; dart format --output=none --set-exit-if-changed --line-length 120 ."
if: "always() && steps.packages_nextcloud_push_proxy_pub_upgrade.conclusion == 'success'"
working-directory: packages/nextcloud_push_proxy
run: "dart format --output=none --set-exit-if-changed --line-length 120 ."
- id: packages_settings_pub_upgrade
name: packages/settings; flutter pub pub upgrade
if: "always() && steps.checkout.conclusion == 'success'"
@ -158,16 +167,16 @@ jobs:
needs:
- job_001
job_004:
name: "analyze; PKGS: packages/nextcloud, packages/sort_box, packages/spec_templates; `dart analyze`"
name: "analyze; PKGS: packages/nextcloud, packages/nextcloud_push_proxy, packages/sort_box, packages/spec_templates; `dart analyze`"
runs-on: ubuntu-latest
steps:
- name: Cache Pub hosted dependencies
uses: actions/cache@4504faf7e9bcf8f3ed0bc863c4e1d21499ab8ef8
with:
path: "~/.pub-cache/hosted"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/nextcloud-packages/sort_box-packages/spec_templates;commands:analyze_1"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/nextcloud-packages/nextcloud_push_proxy-packages/sort_box-packages/spec_templates;commands:analyze_1"
restore-keys: |
os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/nextcloud-packages/sort_box-packages/spec_templates
os:ubuntu-latest;pub-cache-hosted;sdk:stable;packages:packages/nextcloud-packages/nextcloud_push_proxy-packages/sort_box-packages/spec_templates
os:ubuntu-latest;pub-cache-hosted;sdk:stable
os:ubuntu-latest;pub-cache-hosted
os:ubuntu-latest
@ -185,6 +194,15 @@ jobs:
if: "always() && steps.packages_nextcloud_pub_upgrade.conclusion == 'success'"
working-directory: packages/nextcloud
run: dart analyze
- id: packages_nextcloud_push_proxy_pub_upgrade
name: packages/nextcloud_push_proxy; dart pub upgrade
if: "always() && steps.checkout.conclusion == 'success'"
working-directory: packages/nextcloud_push_proxy
run: dart pub upgrade
- name: packages/nextcloud_push_proxy; dart analyze
if: "always() && steps.packages_nextcloud_push_proxy_pub_upgrade.conclusion == 'success'"
working-directory: packages/nextcloud_push_proxy
run: dart analyze
- id: packages_sort_box_pub_upgrade
name: packages/sort_box; dart pub upgrade
if: "always() && steps.checkout.conclusion == 'success'"

3
.gitmodules vendored

@ -13,3 +13,6 @@
[submodule "external/nextcloud-notes"]
path = external/nextcloud-notes
url = https://github.com/nextcloud/notes
[submodule "external/nextcloud-notifications"]
path = external/nextcloud-notifications
url = https://github.com/nextcloud/notifications

5
.idea/nextcloud-harbour.iml

@ -44,6 +44,11 @@
<excludeFolder url="file://$MODULE_DIR$/external" />
<excludeFolder url="file://$MODULE_DIR$/packages/nextcloud/lib/src/clients/common" />
<excludeFolder url="file://$MODULE_DIR$/packages/nextcloud/lib/src/clients/generated" />
<excludeFolder url="file://$MODULE_DIR$/packages/harbour/android/.gradle" />
<excludeFolder url="file://$MODULE_DIR$/packages/harbour/linux/flutter/ephemeral" />
<excludeFolder url="file://$MODULE_DIR$/packages/nextcloud_push_proxy/build" />
<excludeFolder url="file://$MODULE_DIR$/packages/nextcloud_push_proxy/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/packages/nextcloud_push_proxy/.pub" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

1
.idea/vcs.xml

@ -4,6 +4,7 @@
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/external/nextcloud-news" vcs="Git" />
<mapping directory="$PROJECT_DIR$/external/nextcloud-notes" vcs="Git" />
<mapping directory="$PROJECT_DIR$/external/nextcloud-notifications" vcs="Git" />
<mapping directory="$PROJECT_DIR$/external/nextcloud-server" vcs="Git" />
<mapping directory="$PROJECT_DIR$/external/openapi-generator" vcs="Git" />
<mapping directory="$PROJECT_DIR$/external/seti-ui" vcs="Git" />

1
external/nextcloud-notifications vendored

@ -0,0 +1 @@
Subproject commit 62c670f2cf9674b95e2f7b94f7bf0cd3887f3418

16
packages/nextcloud/doc/notifications/AdminNotification.md

@ -0,0 +1,16 @@
# openapi.model.AdminNotification
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**shortMessage** | **String** | | [optional]
**longMessage** | **String** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

318
packages/nextcloud/doc/notifications/DefaultApi.md

@ -0,0 +1,318 @@
# openapi.api.DefaultApi
## Load the API package
```dart
import 'package:openapi/api.dart';
```
All URIs are relative to *https://localhost:8080/ocs/v1.php/apps/notifications*
Method | HTTP request | Description
------------- | ------------- | -------------
[**deleteAllNotifications**](DefaultApi.md#deleteallnotifications) | **DELETE** /api/v2/notifications |
[**deleteNotification**](DefaultApi.md#deletenotification) | **DELETE** /api/v2/notifications/{id} |
[**getNotification**](DefaultApi.md#getnotification) | **GET** /api/v2/notifications/{id} |
[**listNotifications**](DefaultApi.md#listnotifications) | **GET** /api/v2/notifications |
[**registerDevice**](DefaultApi.md#registerdevice) | **POST** /api/v2/push |
[**removeDevice**](DefaultApi.md#removedevice) | **DELETE** /api/v2/push |
[**sendAdminNotification**](DefaultApi.md#sendadminnotification) | **POST** /api/v2/admin_notifications/{userId} |
# **deleteAllNotifications**
> String deleteAllNotifications()
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure HTTP basic authorization: basic_auth
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').username = 'YOUR_USERNAME'
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').password = 'YOUR_PASSWORD';
final api_instance = DefaultApi();
try {
final result = api_instance.deleteAllNotifications();
print(result);
} catch (e) {
print('Exception when calling DefaultApi->deleteAllNotifications: $e\n');
}
```
### Parameters
This endpoint does not need any parameter.
### Return type
**String**
### Authorization
[basic_auth](../README.md#basic_auth)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **deleteNotification**
> EmptyResponse deleteNotification(id)
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure HTTP basic authorization: basic_auth
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').username = 'YOUR_USERNAME'
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').password = 'YOUR_PASSWORD';
final api_instance = DefaultApi();
final id = 56; // int |
try {
final result = api_instance.deleteNotification(id);
print(result);
} catch (e) {
print('Exception when calling DefaultApi->deleteNotification: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**id** | **int**| |
### Return type
[**EmptyResponse**](EmptyResponse.md)
### Authorization
[basic_auth](../README.md#basic_auth)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getNotification**
> GetNotificationResponse getNotification(id)
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure HTTP basic authorization: basic_auth
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').username = 'YOUR_USERNAME'
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').password = 'YOUR_PASSWORD';
final api_instance = DefaultApi();
final id = 56; // int |
try {
final result = api_instance.getNotification(id);
print(result);
} catch (e) {
print('Exception when calling DefaultApi->getNotification: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**id** | **int**| |
### Return type
[**GetNotificationResponse**](GetNotificationResponse.md)
### Authorization
[basic_auth](../README.md#basic_auth)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **listNotifications**
> String listNotifications()
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure HTTP basic authorization: basic_auth
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').username = 'YOUR_USERNAME'
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').password = 'YOUR_PASSWORD';
final api_instance = DefaultApi();
try {
final result = api_instance.listNotifications();
print(result);
} catch (e) {
print('Exception when calling DefaultApi->listNotifications: $e\n');
}
```
### Parameters
This endpoint does not need any parameter.
### Return type
**String**
### Authorization
[basic_auth](../README.md#basic_auth)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **registerDevice**
> PushServerRegistrationResponse registerDevice(pushServerDevice)
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure HTTP basic authorization: basic_auth
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').username = 'YOUR_USERNAME'
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').password = 'YOUR_PASSWORD';
final api_instance = DefaultApi();
final pushServerDevice = PushServerDevice(); // PushServerDevice |
try {
final result = api_instance.registerDevice(pushServerDevice);
print(result);
} catch (e) {
print('Exception when calling DefaultApi->registerDevice: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**pushServerDevice** | [**PushServerDevice**](PushServerDevice.md)| |
### Return type
[**PushServerRegistrationResponse**](PushServerRegistrationResponse.md)
### Authorization
[basic_auth](../README.md#basic_auth)
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **removeDevice**
> String removeDevice()
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure HTTP basic authorization: basic_auth
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').username = 'YOUR_USERNAME'
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').password = 'YOUR_PASSWORD';
final api_instance = DefaultApi();
try {
final result = api_instance.removeDevice();
print(result);
} catch (e) {
print('Exception when calling DefaultApi->removeDevice: $e\n');
}
```
### Parameters
This endpoint does not need any parameter.
### Return type
**String**
### Authorization
[basic_auth](../README.md#basic_auth)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **sendAdminNotification**
> EmptyResponse sendAdminNotification(userId, adminNotification)
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure HTTP basic authorization: basic_auth
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').username = 'YOUR_USERNAME'
//defaultApiClient.getAuthentication<HttpBasicAuth>('basic_auth').password = 'YOUR_PASSWORD';
final api_instance = DefaultApi();
final userId = userId_example; // String |
final adminNotification = AdminNotification(); // AdminNotification |
try {
final result = api_instance.sendAdminNotification(userId, adminNotification);
print(result);
} catch (e) {
print('Exception when calling DefaultApi->sendAdminNotification: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**userId** | **String**| |
**adminNotification** | [**AdminNotification**](AdminNotification.md)| |
### Return type
[**EmptyResponse**](EmptyResponse.md)
### Authorization
[basic_auth](../README.md#basic_auth)
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

15
packages/nextcloud/doc/notifications/EmptyResponse.md

@ -0,0 +1,15 @@
# openapi.model.EmptyResponse
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**ocs** | [**EmptyResponseOcs**](EmptyResponseOcs.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

16
packages/nextcloud/doc/notifications/EmptyResponseOcs.md

@ -0,0 +1,16 @@
# openapi.model.EmptyResponseOcs
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**meta** | [**Object**](.md) | Stub | [optional]
**data** | **List<String>** | | [optional] [default to const []]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

15
packages/nextcloud/doc/notifications/GetNotificationResponse.md

@ -0,0 +1,15 @@
# openapi.model.GetNotificationResponse
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**ocs** | [**GetNotificationResponseOcs**](GetNotificationResponseOcs.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

16
packages/nextcloud/doc/notifications/GetNotificationResponseOcs.md

@ -0,0 +1,16 @@
# openapi.model.GetNotificationResponseOcs
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**meta** | [**Object**](.md) | Stub | [optional]
**data** | [**Notification**](Notification.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

15
packages/nextcloud/doc/notifications/ListNotificationsResponse.md

@ -0,0 +1,15 @@
# openapi.model.ListNotificationsResponse
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**ocs** | [**ListNotificationsResponseOcs**](ListNotificationsResponseOcs.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

16
packages/nextcloud/doc/notifications/ListNotificationsResponseOcs.md

@ -0,0 +1,16 @@
# openapi.model.ListNotificationsResponseOcs
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**meta** | [**Object**](.md) | Stub | [optional]
**data** | [**List<Notification>**](Notification.md) | | [optional] [default to const []]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

29
packages/nextcloud/doc/notifications/Notification.md

@ -0,0 +1,29 @@
# openapi.model.Notification
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**notificationId** | **int** | | [optional]
**app** | **String** | | [optional]
**user** | **String** | | [optional]
**datetime** | **String** | | [optional]
**objectType** | **String** | | [optional]
**objectId** | **String** | | [optional]
**subject** | **String** | | [optional]
**message** | **String** | | [optional]
**link** | **String** | | [optional]
**subjectRich** | **String** | | [optional]
**subjectRichParameters** | **List<String>** | | [optional] [default to const []]
**messageRich** | **String** | | [optional]
**messageRichParameters** | **List<String>** | | [optional] [default to const []]
**icon** | **String** | | [optional]
**actions** | **List<String>** | | [optional] [default to const []]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

19
packages/nextcloud/doc/notifications/PushNotificationDecryptedSubject.md

@ -0,0 +1,19 @@
# openapi.model.PushNotificationDecryptedSubject
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**nid** | **int** | | [optional]
**app** | **String** | | [optional]
**subject** | **String** | | [optional]
**type** | **String** | | [optional]
**id** | **String** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

17
packages/nextcloud/doc/notifications/PushServerDevice.md

@ -0,0 +1,17 @@
# openapi.model.PushServerDevice
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**pushTokenHash** | **String** | | [optional]
**devicePublicKey** | **String** | | [optional]
**proxyServer** | **String** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

15
packages/nextcloud/doc/notifications/PushServerRegistrationResponse.md

@ -0,0 +1,15 @@
# openapi.model.PushServerRegistrationResponse
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**ocs** | [**PushServerRegistrationResponseOcs**](PushServerRegistrationResponseOcs.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

16
packages/nextcloud/doc/notifications/PushServerRegistrationResponseOcs.md

@ -0,0 +1,16 @@
# openapi.model.PushServerRegistrationResponseOcs
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**meta** | [**Object**](.md) | Stub | [optional]
**data** | [**PushServerSubscription**](PushServerSubscription.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

17
packages/nextcloud/doc/notifications/PushServerSubscription.md

@ -0,0 +1,17 @@
# openapi.model.PushServerSubscription
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**publicKey** | **String** | | [optional]
**deviceIdentifier** | **String** | | [optional]
**signature** | **String** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

5
packages/nextcloud/lib/nextcloud.dart

@ -1,5 +1,7 @@
library nextcloud;
export 'package:crypton/crypton.dart' show RSAKeypair, RSAPublicKey, RSAPrivateKey;
export 'src/app_type.dart';
export 'src/client.dart';
export 'src/clients/common/api.dart';
@ -11,12 +13,15 @@ export 'src/clients/generated/news/api.dart'
hide ApiClient, serializeAsync, deserializeAsync, DeserializationMessage, DefaultApi;
export 'src/clients/generated/notes/api.dart'
hide ApiClient, serializeAsync, deserializeAsync, DeserializationMessage, DefaultApi;
export 'src/clients/generated/notifications/api.dart'
hide ApiClient, serializeAsync, deserializeAsync, DeserializationMessage, DefaultApi;
export 'src/clients/generated/provisioning_api/api.dart'
hide ApiClient, serializeAsync, deserializeAsync, DeserializationMessage, DefaultApi;
export 'src/clients/generated/user_status/api.dart'
hide ApiClient, serializeAsync, deserializeAsync, DeserializationMessage, DefaultApi;
export 'src/clients/news.dart';
export 'src/clients/notes.dart';
export 'src/clients/notifications.dart';
export 'src/clients/provisioning_api.dart';
export 'src/clients/user_status.dart';
export 'src/clients/webdav.dart';

9
packages/nextcloud/lib/src/client.dart

@ -29,6 +29,11 @@ class NextcloudClient {
authentication,
_addCommonSettings,
);
_notifications = NextcloudNotificationsClient(
baseURL,
authentication,
_addCommonSettings,
);
_provisioningApi = NextcloudProvisioningApiClient(
baseURL,
authentication,
@ -103,6 +108,7 @@ class NextcloudClient {
late NextcloudCoreClient _core;
late NextcloudNewsClient _news;
late NextcloudNotesClient _notes;
late NextcloudNotificationsClient _notifications;
late NextcloudProvisioningApiClient _provisioningApi;
late NextcloudUserStatusClient _userStatus;
@ -118,6 +124,9 @@ class NextcloudClient {
/// Client for Nextcloud Notes app
NextcloudNotesClient get notes => _notes;
/// Client for Nextcloud Notifications API
NextcloudNotificationsClient get notifications => _notifications;
/// Client for Provisioning APIs
NextcloudProvisioningApiClient get provisioningApi => _provisioningApi;

16
packages/nextcloud/lib/src/clients/custom/webdav/client.dart

@ -30,12 +30,6 @@ class WebDavClient {
'http://sabredav.org/ns': 's', // mostly used in error responses
};
Future<Uint8List> _responseToBodyBytes(final HttpClientResponse response) async =>
Uint8List.fromList((await response.toList()).reduce((final value, final element) => [...value, ...element]));
Future<String> _responseToBodyString(final HttpClientResponse response) async =>
utf8.decode(await _responseToBodyBytes(response));
Future<HttpClientResponse> _send(
final String method,
final String url,
@ -66,7 +60,7 @@ class WebDavClient {
if (!expectedCodes.contains(response.statusCode)) {
throw ApiException(
response.statusCode,
await _responseToBodyString(response),
await response.body,
);
}
@ -233,7 +227,7 @@ class WebDavClient {
return treeFromWebDavXml(
basePath,
namespaces,
await _responseToBodyString(response),
await response.body,
)..removeAt(0);
}
@ -284,7 +278,7 @@ class WebDavClient {
return treeFromWebDavXml(
basePath,
namespaces,
await _responseToBodyString(response),
await response.body,
);
}
@ -306,7 +300,7 @@ class WebDavClient {
return fileFromWebDavXml(
basePath,
namespaces,
await _responseToBodyString(response),
await response.body,
);
}
@ -350,7 +344,7 @@ class WebDavClient {
[200, 207],
data: Stream.value(Uint8List.fromList(utf8.encode(builder.buildDocument().toString()))),
);
return checkUpdateFromWebDavXml(await _responseToBodyString(response));
return checkUpdateFromWebDavXml(await response.body);
}
/// Move a file from [sourcePath] to [destinationPath]

1
packages/nextcloud/lib/src/clients/custom/webdav/webdav.dart

@ -6,6 +6,7 @@ import 'dart:typed_data';
import 'package:intl/intl.dart';
import 'package:nextcloud/src/clients/common/api.dart';
import 'package:nextcloud/src/http_client_response_extension.dart';
import 'package:xml/xml.dart';
import 'package:xml/xml.dart' as xml;

39
packages/nextcloud/lib/src/clients/generated/notifications/api.dart

@ -0,0 +1,39 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
library openapi.api;
import 'package:nextcloud/src/clients/common/api.dart';
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart';
import 'package:intl/intl.dart';
import 'package:meta/meta.dart';
part 'api_client.dart';
part 'api/default_api.dart';
part 'model/admin_notification.dart';
part 'model/empty_response.dart';
part 'model/empty_response_ocs.dart';
part 'model/get_notification_response.dart';
part 'model/get_notification_response_ocs.dart';
part 'model/list_notifications_response.dart';
part 'model/list_notifications_response_ocs.dart';
part 'model/notification.dart';
part 'model/push_notification_decrypted_subject.dart';
part 'model/push_server_device.dart';
part 'model/push_server_registration_response.dart';
part 'model/push_server_registration_response_ocs.dart';
part 'model/push_server_subscription.dart';

364
packages/nextcloud/lib/src/clients/generated/notifications/api/default_api.dart

@ -0,0 +1,364 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class DefaultApi extends ApiInstance<ApiClient> {
DefaultApi(ApiClient apiClient) : super(apiClient);
/// Performs an HTTP 'DELETE /api/v2/notifications' operation and returns the [Response].
Future<Response> deleteAllNotificationsWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/api/v2/notifications';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'DELETE',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<String?> deleteAllNotifications() async {
final response = await deleteAllNotificationsWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(
await decodeBodyBytes(response),
'String',
) as String;
}
return null;
}
/// Performs an HTTP 'DELETE /api/v2/notifications/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [int] id (required):
Future<Response> deleteNotificationWithHttpInfo(
int id,
) async {
// ignore: prefer_const_declarations
final path = r'/api/v2/notifications/{id}'.replaceAll('{id}', id.toString());
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'DELETE',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [int] id (required):
Future<EmptyResponse?> deleteNotification(
int id,
) async {
final response = await deleteNotificationWithHttpInfo(
id,
);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(
await decodeBodyBytes(response),
'EmptyResponse',
) as EmptyResponse;
}
return null;
}
/// Performs an HTTP 'GET /api/v2/notifications/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [int] id (required):
Future<Response> getNotificationWithHttpInfo(
int id,
) async {
// ignore: prefer_const_declarations
final path = r'/api/v2/notifications/{id}'.replaceAll('{id}', id.toString());
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [int] id (required):
Future<GetNotificationResponse?> getNotification(
int id,
) async {
final response = await getNotificationWithHttpInfo(
id,
);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(
await decodeBodyBytes(response),
'GetNotificationResponse',
) as GetNotificationResponse;
}
return null;
}
/// Performs an HTTP 'GET /api/v2/notifications' operation and returns the [Response].
Future<Response> listNotificationsWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/api/v2/notifications';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<String?> listNotifications() async {
final response = await listNotificationsWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(
await decodeBodyBytes(response),
'String',
) as String;
}
return null;
}
/// Performs an HTTP 'POST /api/v2/push' operation and returns the [Response].
/// Parameters:
///
/// * [PushServerDevice] pushServerDevice (required):
Future<Response> registerDeviceWithHttpInfo(
PushServerDevice pushServerDevice,
) async {
// ignore: prefer_const_declarations
final path = r'/api/v2/push';
// ignore: prefer_final_locals
Object? postBody = pushServerDevice;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [PushServerDevice] pushServerDevice (required):
Future<PushServerRegistrationResponse?> registerDevice(
PushServerDevice pushServerDevice,
) async {
final response = await registerDeviceWithHttpInfo(
pushServerDevice,
);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(
await decodeBodyBytes(response),
'PushServerRegistrationResponse',
) as PushServerRegistrationResponse;
}
return null;
}
/// Performs an HTTP 'DELETE /api/v2/push' operation and returns the [Response].
Future<Response> removeDeviceWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/api/v2/push';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'DELETE',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<String?> removeDevice() async {
final response = await removeDeviceWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(
await decodeBodyBytes(response),
'String',
) as String;
}
return null;
}
/// Performs an HTTP 'POST /api/v2/admin_notifications/{userId}' operation and returns the [Response].
/// Parameters:
///
/// * [String] userId (required):
///
/// * [AdminNotification] adminNotification (required):
Future<Response> sendAdminNotificationWithHttpInfo(
String userId,
AdminNotification adminNotification,
) async {
// ignore: prefer_const_declarations
final path = r'/api/v2/admin_notifications/{userId}'.replaceAll('{userId}', userId);
// ignore: prefer_final_locals
Object? postBody = adminNotification;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [String] userId (required):
///
/// * [AdminNotification] adminNotification (required):
Future<EmptyResponse?> sendAdminNotification(
String userId,
AdminNotification adminNotification,
) async {
final response = await sendAdminNotificationWithHttpInfo(
userId,
adminNotification,
);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(
await decodeBodyBytes(response),
'EmptyResponse',
) as EmptyResponse;
}
return null;
}
}

329
packages/nextcloud/lib/src/clients/generated/notifications/api_client.dart

@ -0,0 +1,329 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class ApiClient extends BaseApiClient {
ApiClient({this.basePath = 'https://localhost:8080/ocs/v1.php/apps/notifications', this.authentication});
final String basePath;
var _client = Client();
/// Returns the current HTTP [Client] instance to use in this class.
///
/// The return value is guaranteed to never be null.
Client get client => _client;
/// Requests to use a new HTTP [Client] in this class.
set client(Client newClient) {
_client = newClient;
}
final _defaultHeaderMap = <String, String>{};
final Authentication? authentication;
void addDefaultHeader(String key, String value) {
_defaultHeaderMap[key] = value;
}
Map<String, String> get defaultHeaderMap => _defaultHeaderMap;
// We don't use a Map<String, String> for queryParams.
// If collectionFormat is 'multi', a key might appear multiple times.
Future<Response> invokeAPI(
String path,
String method,
List<QueryParam> queryParams,
Object? body,
Map<String, String> headerParams,
Map<String, String> formParams,
String? contentType,
) async {
_updateParamsForAuth(queryParams, headerParams);
headerParams.addAll(_defaultHeaderMap);
if (contentType != null) {
headerParams['Content-Type'] = contentType;
}
final urlEncodedQueryParams = queryParams.map((param) => '$param');
final queryString = urlEncodedQueryParams.isNotEmpty ? '?${urlEncodedQueryParams.join('&')}' : '';
final uri = Uri.parse('$basePath$path$queryString');
try {
// Special case for uploading a single file which isn't a 'multipart/form-data'.
if (body is MultipartFile &&
(contentType == null || !contentType.toLowerCase().startsWith('multipart/form-data'))) {
final request = StreamedRequest(method, uri);
request.headers.addAll(headerParams);
request.contentLength = body.length;
body.finalize().listen(
request.sink.add,
onDone: request.sink.close,
// ignore: avoid_types_on_closure_parameters
onError: (Object error, StackTrace trace) => request.sink.close(),
cancelOnError: true,
);
final response = await _client.send(request);
return Response.fromStream(response);
}
if (body is MultipartRequest) {
final request = MultipartRequest(method, uri);
request.fields.addAll(body.fields);
request.files.addAll(body.files);
request.headers.addAll(body.headers);
request.headers.addAll(headerParams);
final response = await _client.send(request);
return Response.fromStream(response);
}
final msgBody = contentType == 'application/x-www-form-urlencoded' ? formParams : await serializeAsync(body);
final nullableHeaderParams = headerParams.isEmpty ? null : headerParams;
switch (method) {
case 'POST':
return await _client.post(
uri,
headers: nullableHeaderParams,
body: msgBody,
);
case 'PUT':
return await _client.put(
uri,
headers: nullableHeaderParams,
body: msgBody,
);
case 'DELETE':
return await _client.delete(
uri,
headers: nullableHeaderParams,
body: msgBody,
);
case 'PATCH':
return await _client.patch(
uri,
headers: nullableHeaderParams,
body: msgBody,
);
case 'HEAD':
return await _client.head(
uri,
headers: nullableHeaderParams,
);
case 'GET':
return await _client.get(
uri,
headers: nullableHeaderParams,
);
}
} on SocketException catch (error, trace) {
throw ApiException.withInner(
HttpStatus.badRequest,
'Socket operation failed: $method $path',
error,
trace,
);
} on TlsException catch (error, trace) {
throw ApiException.withInner(
HttpStatus.badRequest,
'TLS/SSL communication failed: $method $path',
error,
trace,
);
} on IOException catch (error, trace) {
throw ApiException.withInner(
HttpStatus.badRequest,
'I/O operation failed: $method $path',
error,
trace,
);
} on ClientException catch (error, trace) {
throw ApiException.withInner(
HttpStatus.badRequest,
'HTTP connection failed: $method $path',
error,
trace,
);
} on Exception catch (error, trace) {
throw ApiException.withInner(
HttpStatus.badRequest,
'Exception occurred: $method $path',
error,
trace,
);
}
throw ApiException(
HttpStatus.badRequest,
'Invalid HTTP operation: $method $path',
);
}
Future<dynamic> deserializeAsync(
String json,
String targetType, {
bool growable = false,
}) async =>
// ignore: deprecated_member_use_from_same_package
deserialize(json, targetType, growable: growable);
@Deprecated('Scheduled for removal in OpenAPI Generator 6.x. Use deserializeAsync() instead.')
dynamic deserialize(
String json,
String targetType, {
bool growable = false,
}) {
// Remove all spaces. Necessary for regular expressions as well.
targetType = targetType.replaceAll(' ', ''); // ignore: parameter_assignments
// If the expected target type is String, nothing to do...
return targetType == 'String' ? json : _deserialize(jsonDecode(json), targetType, growable: growable);
}
// ignore: deprecated_member_use_from_same_package
Future<String> serializeAsync(Object? value) async => serialize(value);
@Deprecated('Scheduled for removal in OpenAPI Generator 6.x. Use serializeAsync() instead.')
String serialize(Object? value) => value == null ? '' : json.encode(value);
/// Update query and header parameters based on authentication settings.
void _updateParamsForAuth(
List<QueryParam> queryParams,
Map<String, String> headerParams,
) {
if (authentication != null) {
authentication!.applyToParams(queryParams, headerParams);
}
}
static dynamic _deserialize(dynamic value, String targetType, {bool growable = false}) {
try {
switch (targetType) {
case 'String':
return value is String ? value : value.toString();
case 'int':
return value is int ? value : int.parse('$value');
case 'double':
return value is double ? value : double.parse('$value');
case 'bool':
if (value is bool) {
return value;
}
final valueString = '$value'.toLowerCase();
return valueString == 'true' || valueString == '1';
case 'AdminNotification':
return AdminNotification.fromJson(value);
case 'EmptyResponse':
return EmptyResponse.fromJson(value);
case 'EmptyResponseOcs':
return EmptyResponseOcs.fromJson(value);
case 'GetNotificationResponse':
return GetNotificationResponse.fromJson(value);
case 'GetNotificationResponseOcs':
return GetNotificationResponseOcs.fromJson(value);
case 'ListNotificationsResponse':
return ListNotificationsResponse.fromJson(value);
case 'ListNotificationsResponseOcs':
return ListNotificationsResponseOcs.fromJson(value);
case 'Notification':
return Notification.fromJson(value);
case 'PushNotificationDecryptedSubject':
return PushNotificationDecryptedSubject.fromJson(value);
case 'PushServerDevice':
return PushServerDevice.fromJson(value);
case 'PushServerRegistrationResponse':
return PushServerRegistrationResponse.fromJson(value);
case 'PushServerRegistrationResponseOcs':
return PushServerRegistrationResponseOcs.fromJson(value);
case 'PushServerSubscription':
return PushServerSubscription.fromJson(value);
default:
dynamic match;
if (value is List && (match = apiRegList.firstMatch(targetType)?.group(1)) != null) {
return value
.map<dynamic>((dynamic v) => _deserialize(
v,
match,
growable: growable,
))
.toList(growable: growable);
}
if (value is Set && (match = apiRegSet.firstMatch(targetType)?.group(1)) != null) {
return value
.map<dynamic>((dynamic v) => _deserialize(
v,
match,
growable: growable,
))
.toSet();
}
if (value is Map && (match = apiRegMap.firstMatch(targetType)?.group(1)) != null) {
return Map<String, dynamic>.fromIterables(
value.keys.cast<String>(),
value.values.map<dynamic>((dynamic v) => _deserialize(
v,
match,
growable: growable,
)),
);
}
}
} on Exception catch (error, trace) {
throw ApiException.withInner(
HttpStatus.internalServerError,
'Exception during deserialization.',
error,
trace,
);
}
throw ApiException(
HttpStatus.internalServerError,
'Could not find a suitable class for deserialization',
);
}
}
/// Primarily intended for use in an isolate.
class DeserializationMessage {
const DeserializationMessage({
required this.json,
required this.targetType,
this.growable = false,
});
/// The JSON value to deserialize.
final String json;
/// Target type to deserialize to.
final String targetType;
/// Whether to make deserialized lists or maps growable.
final bool growable;
}
/// Primarily intended for use in an isolate.
Future<dynamic> deserializeAsync(DeserializationMessage message) async {
// Remove all spaces. Necessary for regular expressions as well.
final targetType = message.targetType.replaceAll(' ', '');
// If the expected target type is String, nothing to do...
return targetType == 'String'
? message.json
: ApiClient._deserialize(
jsonDecode(message.json),
targetType,
growable: message.growable,
);
}
/// Primarily intended for use in an isolate.
Future<String> serializeAsync(Object? value) async => value == null ? '' : json.encode(value);

139
packages/nextcloud/lib/src/clients/generated/notifications/model/admin_notification.dart

@ -0,0 +1,139 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class AdminNotification {
/// Returns a new [AdminNotification] instance.
AdminNotification({
this.shortMessage,
this.longMessage,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? shortMessage;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? longMessage;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is AdminNotification && other.shortMessage == shortMessage && other.longMessage == longMessage;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(shortMessage == null ? 0 : shortMessage!.hashCode) + (longMessage == null ? 0 : longMessage!.hashCode);
@override
String toString() => 'AdminNotification[shortMessage=$shortMessage, longMessage=$longMessage]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (shortMessage != null) {
_json[r'shortMessage'] = shortMessage;
}
if (longMessage != null) {
_json[r'longMessage'] = longMessage;
}
return _json;
}
/// Returns a new [AdminNotification] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static AdminNotification? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "AdminNotification[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "AdminNotification[$key]" has a null value in JSON.');
});
return true;
}());
return AdminNotification(
shortMessage: mapValueOfType<String>(json, r'shortMessage'),
longMessage: mapValueOfType<String>(json, r'longMessage'),
);
}
return null;
}
static List<AdminNotification>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <AdminNotification>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = AdminNotification.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, AdminNotification> mapFromJson(dynamic json) {
final map = <String, AdminNotification>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = AdminNotification.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of AdminNotification-objects as value to a dart map
static Map<String, List<AdminNotification>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<AdminNotification>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = AdminNotification.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

124
packages/nextcloud/lib/src/clients/generated/notifications/model/empty_response.dart

@ -0,0 +1,124 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class EmptyResponse {
/// Returns a new [EmptyResponse] instance.
EmptyResponse({
this.ocs,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
EmptyResponseOcs? ocs;
@override
bool operator ==(Object other) => identical(this, other) || other is EmptyResponse && other.ocs == ocs;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(ocs == null ? 0 : ocs!.hashCode);
@override
String toString() => 'EmptyResponse[ocs=$ocs]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (ocs != null) {
_json[r'ocs'] = ocs;
}
return _json;
}
/// Returns a new [EmptyResponse] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static EmptyResponse? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "EmptyResponse[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "EmptyResponse[$key]" has a null value in JSON.');
});
return true;
}());
return EmptyResponse(
ocs: EmptyResponseOcs.fromJson(json[r'ocs']),
);
}
return null;
}
static List<EmptyResponse>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <EmptyResponse>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = EmptyResponse.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, EmptyResponse> mapFromJson(dynamic json) {
final map = <String, EmptyResponse>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = EmptyResponse.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of EmptyResponse-objects as value to a dart map
static Map<String, List<EmptyResponse>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<EmptyResponse>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = EmptyResponse.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

125
packages/nextcloud/lib/src/clients/generated/notifications/model/empty_response_ocs.dart

@ -0,0 +1,125 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class EmptyResponseOcs {
/// Returns a new [EmptyResponseOcs] instance.
EmptyResponseOcs({
this.meta,
this.data = const [],
});
/// Stub
Object? meta;
List<String> data;
@override
bool operator ==(Object other) =>
identical(this, other) || other is EmptyResponseOcs && other.meta == meta && other.data == data;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(meta == null ? 0 : meta!.hashCode) + (data.hashCode);
@override
String toString() => 'EmptyResponseOcs[meta=$meta, data=$data]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (meta != null) {
_json[r'meta'] = meta;
}
_json[r'data'] = data;
return _json;
}
/// Returns a new [EmptyResponseOcs] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static EmptyResponseOcs? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "EmptyResponseOcs[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "EmptyResponseOcs[$key]" has a null value in JSON.');
});
return true;
}());
return EmptyResponseOcs(
meta: mapValueOfType<Object>(json, r'meta'),
data: json[r'data'] is List ? (json[r'data'] as List).cast<String>() : const [],
);
}
return null;
}
static List<EmptyResponseOcs>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <EmptyResponseOcs>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = EmptyResponseOcs.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, EmptyResponseOcs> mapFromJson(dynamic json) {
final map = <String, EmptyResponseOcs>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = EmptyResponseOcs.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of EmptyResponseOcs-objects as value to a dart map
static Map<String, List<EmptyResponseOcs>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<EmptyResponseOcs>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = EmptyResponseOcs.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

124
packages/nextcloud/lib/src/clients/generated/notifications/model/get_notification_response.dart

@ -0,0 +1,124 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class GetNotificationResponse {
/// Returns a new [GetNotificationResponse] instance.
GetNotificationResponse({
this.ocs,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
GetNotificationResponseOcs? ocs;
@override
bool operator ==(Object other) => identical(this, other) || other is GetNotificationResponse && other.ocs == ocs;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(ocs == null ? 0 : ocs!.hashCode);
@override
String toString() => 'GetNotificationResponse[ocs=$ocs]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (ocs != null) {
_json[r'ocs'] = ocs;
}
return _json;
}
/// Returns a new [GetNotificationResponse] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static GetNotificationResponse? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "GetNotificationResponse[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "GetNotificationResponse[$key]" has a null value in JSON.');
});
return true;
}());
return GetNotificationResponse(
ocs: GetNotificationResponseOcs.fromJson(json[r'ocs']),
);
}
return null;
}
static List<GetNotificationResponse>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <GetNotificationResponse>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = GetNotificationResponse.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, GetNotificationResponse> mapFromJson(dynamic json) {
final map = <String, GetNotificationResponse>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = GetNotificationResponse.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of GetNotificationResponse-objects as value to a dart map
static Map<String, List<GetNotificationResponse>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<GetNotificationResponse>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = GetNotificationResponse.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

133
packages/nextcloud/lib/src/clients/generated/notifications/model/get_notification_response_ocs.dart

@ -0,0 +1,133 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class GetNotificationResponseOcs {
/// Returns a new [GetNotificationResponseOcs] instance.
GetNotificationResponseOcs({
this.meta,
this.data,
});
/// Stub
Object? meta;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
Notification? data;
@override
bool operator ==(Object other) =>
identical(this, other) || other is GetNotificationResponseOcs && other.meta == meta && other.data == data;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(meta == null ? 0 : meta!.hashCode) + (data == null ? 0 : data!.hashCode);
@override
String toString() => 'GetNotificationResponseOcs[meta=$meta, data=$data]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (meta != null) {
_json[r'meta'] = meta;
}
if (data != null) {
_json[r'data'] = data;
}
return _json;
}
/// Returns a new [GetNotificationResponseOcs] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static GetNotificationResponseOcs? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "GetNotificationResponseOcs[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "GetNotificationResponseOcs[$key]" has a null value in JSON.');
});
return true;
}());
return GetNotificationResponseOcs(
meta: mapValueOfType<Object>(json, r'meta'),
data: Notification.fromJson(json[r'data']),
);
}
return null;
}
static List<GetNotificationResponseOcs>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <GetNotificationResponseOcs>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = GetNotificationResponseOcs.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, GetNotificationResponseOcs> mapFromJson(dynamic json) {
final map = <String, GetNotificationResponseOcs>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = GetNotificationResponseOcs.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of GetNotificationResponseOcs-objects as value to a dart map
static Map<String, List<GetNotificationResponseOcs>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<GetNotificationResponseOcs>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = GetNotificationResponseOcs.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

124
packages/nextcloud/lib/src/clients/generated/notifications/model/list_notifications_response.dart

@ -0,0 +1,124 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class ListNotificationsResponse {
/// Returns a new [ListNotificationsResponse] instance.
ListNotificationsResponse({
this.ocs,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
ListNotificationsResponseOcs? ocs;
@override
bool operator ==(Object other) => identical(this, other) || other is ListNotificationsResponse && other.ocs == ocs;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(ocs == null ? 0 : ocs!.hashCode);
@override
String toString() => 'ListNotificationsResponse[ocs=$ocs]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (ocs != null) {
_json[r'ocs'] = ocs;
}
return _json;
}
/// Returns a new [ListNotificationsResponse] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static ListNotificationsResponse? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "ListNotificationsResponse[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "ListNotificationsResponse[$key]" has a null value in JSON.');
});
return true;
}());
return ListNotificationsResponse(
ocs: ListNotificationsResponseOcs.fromJson(json[r'ocs']),
);
}
return null;
}
static List<ListNotificationsResponse>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <ListNotificationsResponse>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = ListNotificationsResponse.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, ListNotificationsResponse> mapFromJson(dynamic json) {
final map = <String, ListNotificationsResponse>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = ListNotificationsResponse.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of ListNotificationsResponse-objects as value to a dart map
static Map<String, List<ListNotificationsResponse>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<ListNotificationsResponse>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = ListNotificationsResponse.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

125
packages/nextcloud/lib/src/clients/generated/notifications/model/list_notifications_response_ocs.dart

@ -0,0 +1,125 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class ListNotificationsResponseOcs {
/// Returns a new [ListNotificationsResponseOcs] instance.
ListNotificationsResponseOcs({
this.meta,
this.data = const [],
});
/// Stub
Object? meta;
List<Notification> data;
@override
bool operator ==(Object other) =>
identical(this, other) || other is ListNotificationsResponseOcs && other.meta == meta && other.data == data;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(meta == null ? 0 : meta!.hashCode) + (data.hashCode);
@override
String toString() => 'ListNotificationsResponseOcs[meta=$meta, data=$data]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (meta != null) {
_json[r'meta'] = meta;
}
_json[r'data'] = data;
return _json;
}
/// Returns a new [ListNotificationsResponseOcs] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static ListNotificationsResponseOcs? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "ListNotificationsResponseOcs[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "ListNotificationsResponseOcs[$key]" has a null value in JSON.');
});
return true;
}());
return ListNotificationsResponseOcs(
meta: mapValueOfType<Object>(json, r'meta'),
data: Notification.listFromJson(json[r'data']) ?? const [],
);
}
return null;
}
static List<ListNotificationsResponseOcs>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <ListNotificationsResponseOcs>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = ListNotificationsResponseOcs.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, ListNotificationsResponseOcs> mapFromJson(dynamic json) {
final map = <String, ListNotificationsResponseOcs>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = ListNotificationsResponseOcs.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of ListNotificationsResponseOcs-objects as value to a dart map
static Map<String, List<ListNotificationsResponseOcs>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<ListNotificationsResponseOcs>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = ListNotificationsResponseOcs.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

316
packages/nextcloud/lib/src/clients/generated/notifications/model/notification.dart

@ -0,0 +1,316 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class Notification {
/// Returns a new [Notification] instance.
Notification({
this.notificationId,
this.app,
this.user,
this.datetime,
this.objectType,
this.objectId,
this.subject,
this.message,
this.link,
this.subjectRich,
this.subjectRichParameters = const [],
this.messageRich,
this.messageRichParameters = const [],
this.icon,
this.actions = const [],
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
int? notificationId;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? app;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? user;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? datetime;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? objectType;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? objectId;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? subject;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? message;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? link;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? subjectRich;
List<String> subjectRichParameters;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? messageRich;
List<String> messageRichParameters;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? icon;
List<String> actions;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Notification &&
other.notificationId == notificationId &&
other.app == app &&
other.user == user &&
other.datetime == datetime &&
other.objectType == objectType &&
other.objectId == objectId &&
other.subject == subject &&
other.message == message &&
other.link == link &&
other.subjectRich == subjectRich &&
other.subjectRichParameters == subjectRichParameters &&
other.messageRich == messageRich &&
other.messageRichParameters == messageRichParameters &&
other.icon == icon &&
other.actions == actions;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(notificationId == null ? 0 : notificationId!.hashCode) +
(app == null ? 0 : app!.hashCode) +
(user == null ? 0 : user!.hashCode) +
(datetime == null ? 0 : datetime!.hashCode) +
(objectType == null ? 0 : objectType!.hashCode) +
(objectId == null ? 0 : objectId!.hashCode) +
(subject == null ? 0 : subject!.hashCode) +
(message == null ? 0 : message!.hashCode) +
(link == null ? 0 : link!.hashCode) +
(subjectRich == null ? 0 : subjectRich!.hashCode) +
(subjectRichParameters.hashCode) +
(messageRich == null ? 0 : messageRich!.hashCode) +
(messageRichParameters.hashCode) +
(icon == null ? 0 : icon!.hashCode) +
(actions.hashCode);
@override
String toString() =>
'Notification[notificationId=$notificationId, app=$app, user=$user, datetime=$datetime, objectType=$objectType, objectId=$objectId, subject=$subject, message=$message, link=$link, subjectRich=$subjectRich, subjectRichParameters=$subjectRichParameters, messageRich=$messageRich, messageRichParameters=$messageRichParameters, icon=$icon, actions=$actions]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (notificationId != null) {
_json[r'notification_id'] = notificationId;
}
if (app != null) {
_json[r'app'] = app;
}
if (user != null) {
_json[r'user'] = user;
}
if (datetime != null) {
_json[r'datetime'] = datetime;
}
if (objectType != null) {
_json[r'object_type'] = objectType;
}
if (objectId != null) {
_json[r'object_id'] = objectId;
}
if (subject != null) {
_json[r'subject'] = subject;
}
if (message != null) {
_json[r'message'] = message;
}
if (link != null) {
_json[r'link'] = link;
}
if (subjectRich != null) {
_json[r'subjectRich'] = subjectRich;
}
_json[r'subjectRichParameters'] = subjectRichParameters;
if (messageRich != null) {
_json[r'messageRich'] = messageRich;
}
_json[r'messageRichParameters'] = messageRichParameters;
if (icon != null) {
_json[r'icon'] = icon;
}
_json[r'actions'] = actions;
return _json;
}
/// Returns a new [Notification] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static Notification? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "Notification[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "Notification[$key]" has a null value in JSON.');
});
return true;
}());
return Notification(
notificationId: mapValueOfType<int>(json, r'notification_id'),
app: mapValueOfType<String>(json, r'app'),
user: mapValueOfType<String>(json, r'user'),
datetime: mapValueOfType<String>(json, r'datetime'),
objectType: mapValueOfType<String>(json, r'object_type'),
objectId: mapValueOfType<String>(json, r'object_id'),
subject: mapValueOfType<String>(json, r'subject'),
message: mapValueOfType<String>(json, r'message'),
link: mapValueOfType<String>(json, r'link'),
subjectRich: mapValueOfType<String>(json, r'subjectRich'),
subjectRichParameters:
json[r'subjectRichParameters'] is List ? (json[r'subjectRichParameters'] as List).cast<String>() : const [],
messageRich: mapValueOfType<String>(json, r'messageRich'),
messageRichParameters:
json[r'messageRichParameters'] is List ? (json[r'messageRichParameters'] as List).cast<String>() : const [],
icon: mapValueOfType<String>(json, r'icon'),
actions: json[r'actions'] is List ? (json[r'actions'] as List).cast<String>() : const [],
);
}
return null;
}
static List<Notification>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <Notification>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = Notification.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, Notification> mapFromJson(dynamic json) {
final map = <String, Notification>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = Notification.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of Notification-objects as value to a dart map
static Map<String, List<Notification>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<Notification>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = Notification.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

187
packages/nextcloud/lib/src/clients/generated/notifications/model/push_notification_decrypted_subject.dart

@ -0,0 +1,187 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class PushNotificationDecryptedSubject {
/// Returns a new [PushNotificationDecryptedSubject] instance.
PushNotificationDecryptedSubject({
this.nid,
this.app,
this.subject,
this.type,
this.id,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
int? nid;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? app;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? subject;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? type;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? id;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is PushNotificationDecryptedSubject &&
other.nid == nid &&
other.app == app &&
other.subject == subject &&
other.type == type &&
other.id == id;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(nid == null ? 0 : nid!.hashCode) +
(app == null ? 0 : app!.hashCode) +
(subject == null ? 0 : subject!.hashCode) +
(type == null ? 0 : type!.hashCode) +
(id == null ? 0 : id!.hashCode);
@override
String toString() => 'PushNotificationDecryptedSubject[nid=$nid, app=$app, subject=$subject, type=$type, id=$id]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (nid != null) {
_json[r'nid'] = nid;
}
if (app != null) {
_json[r'app'] = app;
}
if (subject != null) {
_json[r'subject'] = subject;
}
if (type != null) {
_json[r'type'] = type;
}
if (id != null) {
_json[r'id'] = id;
}
return _json;
}
/// Returns a new [PushNotificationDecryptedSubject] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static PushNotificationDecryptedSubject? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "PushNotificationDecryptedSubject[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "PushNotificationDecryptedSubject[$key]" has a null value in JSON.');
});
return true;
}());
return PushNotificationDecryptedSubject(
nid: mapValueOfType<int>(json, r'nid'),
app: mapValueOfType<String>(json, r'app'),
subject: mapValueOfType<String>(json, r'subject'),
type: mapValueOfType<String>(json, r'type'),
id: mapValueOfType<String>(json, r'id'),
);
}
return null;
}
static List<PushNotificationDecryptedSubject>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <PushNotificationDecryptedSubject>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = PushNotificationDecryptedSubject.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, PushNotificationDecryptedSubject> mapFromJson(dynamic json) {
final map = <String, PushNotificationDecryptedSubject>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PushNotificationDecryptedSubject.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of PushNotificationDecryptedSubject-objects as value to a dart map
static Map<String, List<PushNotificationDecryptedSubject>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<PushNotificationDecryptedSubject>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PushNotificationDecryptedSubject.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

158
packages/nextcloud/lib/src/clients/generated/notifications/model/push_server_device.dart

@ -0,0 +1,158 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class PushServerDevice {
/// Returns a new [PushServerDevice] instance.
PushServerDevice({
this.pushTokenHash,
this.devicePublicKey,
this.proxyServer,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? pushTokenHash;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? devicePublicKey;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? proxyServer;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is PushServerDevice &&
other.pushTokenHash == pushTokenHash &&
other.devicePublicKey == devicePublicKey &&
other.proxyServer == proxyServer;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(pushTokenHash == null ? 0 : pushTokenHash!.hashCode) +
(devicePublicKey == null ? 0 : devicePublicKey!.hashCode) +
(proxyServer == null ? 0 : proxyServer!.hashCode);
@override
String toString() =>
'PushServerDevice[pushTokenHash=$pushTokenHash, devicePublicKey=$devicePublicKey, proxyServer=$proxyServer]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (pushTokenHash != null) {
_json[r'pushTokenHash'] = pushTokenHash;
}
if (devicePublicKey != null) {
_json[r'devicePublicKey'] = devicePublicKey;
}
if (proxyServer != null) {
_json[r'proxyServer'] = proxyServer;
}
return _json;
}
/// Returns a new [PushServerDevice] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static PushServerDevice? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "PushServerDevice[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "PushServerDevice[$key]" has a null value in JSON.');
});
return true;
}());
return PushServerDevice(
pushTokenHash: mapValueOfType<String>(json, r'pushTokenHash'),
devicePublicKey: mapValueOfType<String>(json, r'devicePublicKey'),
proxyServer: mapValueOfType<String>(json, r'proxyServer'),
);
}
return null;
}
static List<PushServerDevice>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <PushServerDevice>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = PushServerDevice.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, PushServerDevice> mapFromJson(dynamic json) {
final map = <String, PushServerDevice>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PushServerDevice.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of PushServerDevice-objects as value to a dart map
static Map<String, List<PushServerDevice>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<PushServerDevice>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PushServerDevice.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

125
packages/nextcloud/lib/src/clients/generated/notifications/model/push_server_registration_response.dart

@ -0,0 +1,125 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class PushServerRegistrationResponse {
/// Returns a new [PushServerRegistrationResponse] instance.
PushServerRegistrationResponse({
this.ocs,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
PushServerRegistrationResponseOcs? ocs;
@override
bool operator ==(Object other) =>
identical(this, other) || other is PushServerRegistrationResponse && other.ocs == ocs;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(ocs == null ? 0 : ocs!.hashCode);
@override
String toString() => 'PushServerRegistrationResponse[ocs=$ocs]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (ocs != null) {
_json[r'ocs'] = ocs;
}
return _json;
}
/// Returns a new [PushServerRegistrationResponse] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static PushServerRegistrationResponse? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "PushServerRegistrationResponse[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "PushServerRegistrationResponse[$key]" has a null value in JSON.');
});
return true;
}());
return PushServerRegistrationResponse(
ocs: PushServerRegistrationResponseOcs.fromJson(json[r'ocs']),
);
}
return null;
}
static List<PushServerRegistrationResponse>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <PushServerRegistrationResponse>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = PushServerRegistrationResponse.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, PushServerRegistrationResponse> mapFromJson(dynamic json) {
final map = <String, PushServerRegistrationResponse>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PushServerRegistrationResponse.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of PushServerRegistrationResponse-objects as value to a dart map
static Map<String, List<PushServerRegistrationResponse>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<PushServerRegistrationResponse>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PushServerRegistrationResponse.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

133
packages/nextcloud/lib/src/clients/generated/notifications/model/push_server_registration_response_ocs.dart

@ -0,0 +1,133 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class PushServerRegistrationResponseOcs {
/// Returns a new [PushServerRegistrationResponseOcs] instance.
PushServerRegistrationResponseOcs({
this.meta,
this.data,
});
/// Stub
Object? meta;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
PushServerSubscription? data;
@override
bool operator ==(Object other) =>
identical(this, other) || other is PushServerRegistrationResponseOcs && other.meta == meta && other.data == data;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(meta == null ? 0 : meta!.hashCode) + (data == null ? 0 : data!.hashCode);
@override
String toString() => 'PushServerRegistrationResponseOcs[meta=$meta, data=$data]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (meta != null) {
_json[r'meta'] = meta;
}
if (data != null) {
_json[r'data'] = data;
}
return _json;
}
/// Returns a new [PushServerRegistrationResponseOcs] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static PushServerRegistrationResponseOcs? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "PushServerRegistrationResponseOcs[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "PushServerRegistrationResponseOcs[$key]" has a null value in JSON.');
});
return true;
}());
return PushServerRegistrationResponseOcs(
meta: mapValueOfType<Object>(json, r'meta'),
data: PushServerSubscription.fromJson(json[r'data']),
);
}
return null;
}
static List<PushServerRegistrationResponseOcs>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <PushServerRegistrationResponseOcs>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = PushServerRegistrationResponseOcs.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, PushServerRegistrationResponseOcs> mapFromJson(dynamic json) {
final map = <String, PushServerRegistrationResponseOcs>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PushServerRegistrationResponseOcs.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of PushServerRegistrationResponseOcs-objects as value to a dart map
static Map<String, List<PushServerRegistrationResponseOcs>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<PushServerRegistrationResponseOcs>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PushServerRegistrationResponseOcs.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

158
packages/nextcloud/lib/src/clients/generated/notifications/model/push_server_subscription.dart

@ -0,0 +1,158 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class PushServerSubscription {
/// Returns a new [PushServerSubscription] instance.
PushServerSubscription({
this.publicKey,
this.deviceIdentifier,
this.signature,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? publicKey;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? deviceIdentifier;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? signature;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is PushServerSubscription &&
other.publicKey == publicKey &&
other.deviceIdentifier == deviceIdentifier &&
other.signature == signature;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(publicKey == null ? 0 : publicKey!.hashCode) +
(deviceIdentifier == null ? 0 : deviceIdentifier!.hashCode) +
(signature == null ? 0 : signature!.hashCode);
@override
String toString() =>
'PushServerSubscription[publicKey=$publicKey, deviceIdentifier=$deviceIdentifier, signature=$signature]';
Map<String, dynamic> toJson() {
final _json = <String, dynamic>{};
if (publicKey != null) {
_json[r'publicKey'] = publicKey;
}
if (deviceIdentifier != null) {
_json[r'deviceIdentifier'] = deviceIdentifier;
}
if (signature != null) {
_json[r'signature'] = signature;
}
return _json;
}
/// Returns a new [PushServerSubscription] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static PushServerSubscription? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key), 'Required key "PushServerSubscription[$key]" is missing from JSON.');
assert(json[key] != null, 'Required key "PushServerSubscription[$key]" has a null value in JSON.');
});
return true;
}());
return PushServerSubscription(
publicKey: mapValueOfType<String>(json, r'publicKey'),
deviceIdentifier: mapValueOfType<String>(json, r'deviceIdentifier'),
signature: mapValueOfType<String>(json, r'signature'),
);
}
return null;
}
static List<PushServerSubscription>? listFromJson(
dynamic json, {
bool growable = false,
}) {
final result = <PushServerSubscription>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = PushServerSubscription.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, PushServerSubscription> mapFromJson(dynamic json) {
final map = <String, PushServerSubscription>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PushServerSubscription.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of PushServerSubscription-objects as value to a dart map
static Map<String, List<PushServerSubscription>> mapListFromJson(
dynamic json, {
bool growable = false,
}) {
final map = <String, List<PushServerSubscription>>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = PushServerSubscription.listFromJson(
entry.value,
growable: growable,
);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{};
}

98
packages/nextcloud/lib/src/clients/notifications.dart

@ -0,0 +1,98 @@
import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:crypton/crypton.dart';
import 'package:nextcloud/src/clients/common/api.dart';
import 'package:nextcloud/src/clients/generated/notifications/api.dart';
import 'package:nextcloud/src/http_client_response_extension.dart';
// ignore: public_member_api_docs
class NextcloudNotificationsClient extends DefaultApi {
// ignore: public_member_api_docs
NextcloudNotificationsClient(
final String baseURL,
final Authentication authentication,
final ApiClient Function(ApiClient) addCommonSettings,
) : super(
addCommonSettings(
ApiClient(
basePath: '$baseURL/ocs/v1.php/apps/notifications',
authentication: authentication,
),
),
);
@override
@Deprecated('Use registerDeviceAtServer instead')
Future<PushServerRegistrationResponse?> registerDevice(PushServerDevice pushServerDevice) =>
throw Exception('Use registerDeviceAtServer instead');
/// Registers a device at the Nextcloud server
Future<PushServerRegistrationResponse?> registerDeviceAtServer(
final String pushToken,
final RSAPublicKey devicePublicKey,
final String proxyServer,
) {
_validateProxyServerURL(proxyServer);
return super.registerDevice(
PushServerDevice(
pushTokenHash: generatePushTokenHash(pushToken),
devicePublicKey: devicePublicKey.toFormattedPEM(),
proxyServer: proxyServer,
),
);
}
/// Registers a device at the push proxy server
Future registerDeviceAtPushProxy(
final String pushToken,
final PushServerSubscription subscription,
final String proxyServer,
) async {
_validateProxyServerURL(proxyServer);
final request = await HttpClient().postUrl(Uri.parse('${proxyServer}devices'))
..followRedirects = false
..persistentConnection = true;
request.headers.add(HttpHeaders.contentTypeHeader, 'application/x-www-form-urlencoded');
request.add(
utf8.encode(
Uri(
queryParameters: {
'pushToken': pushToken,
'deviceIdentifier': subscription.deviceIdentifier!,
'deviceIdentifierSignature': subscription.signature!,
'userPublicKey': subscription.publicKey!,
},
).query,
),
);
final response = await request.close();
if (response.statusCode != 200) {
throw ApiException(
response.statusCode,
await response.body,
);
}
}
/// Generates the push token hash which is just sha512
String generatePushTokenHash(final String pushToken) => sha512.convert(utf8.encode(pushToken)).toString();
/// Decrypts the subject of a push notification
PushNotificationDecryptedSubject decryptPushNotificationSubject(
final RSAPrivateKey privateKey,
final String subject,
) =>
PushNotificationDecryptedSubject.fromJson(json.decode(privateKey.decrypt(subject)) as Map<String, dynamic>)!;
void _validateProxyServerURL(final String proxyServer) {
if (!proxyServer.endsWith('/')) {
throw Exception('proxyServer URL has to end with a /');
}
}
}

12
packages/nextcloud/lib/src/http_client_response_extension.dart

@ -0,0 +1,12 @@
// ignore_for_file: public_member_api_docs
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
extension HttpClientResponseBody on HttpClientResponse {
Future<Uint8List> get bodyBytes async =>
Uint8List.fromList((await toList()).reduce((final value, final element) => [...value, ...element]));
Future<String> get body async => utf8.decode(await bodyBytes);
}

5
packages/nextcloud/pubspec.yaml

@ -5,6 +5,8 @@ environment:
sdk: '>=2.17.0 <3.0.0'
dependencies:
crypto: ^3.0.2
crypton: ^2.0.5
http: ^0.13.4
intl: ^0.17.0
meta: ^1.7.0
@ -12,7 +14,8 @@ dependencies:
dev_dependencies:
# coverage: ^1.3.2
crypto: ^3.0.1
nextcloud_push_proxy:
path: ../nextcloud_push_proxy
nit_picking:
git:
url: https://github.com/stack11/dart_nit_picking

48
packages/nextcloud/test/helper.dart

@ -136,10 +136,14 @@ class TestHelper {
final String dockerImageName, {
final String? username = defaultUsername,
final String? password = defaultPassword,
final bool useAppPassword = false,
final AppType appType = AppType.unknown,
final String? userAgentSuffix,
}) async {
final port = 1024 + Random().nextInt(65535 - 1024);
// ignore: prefer_asserts_with_message
assert(!useAppPassword || (username != null && password != null));
final port = randomPort();
final result = await runExecutableArguments(
'docker',
@ -149,6 +153,8 @@ class TestHelper {
'-d',
'-p',
'$port:80',
'--add-host',
'host.docker.internal:host-gateway',
dockerImageName,
],
);
@ -159,11 +165,38 @@ class TestHelper {
final containerID = result.stdout.toString().replaceAll('\n', '');
var clientPassword = password;
if (useAppPassword) {
final inputStream = StreamController<List<int>>();
final process = runExecutableArguments(
'docker',
[
'exec',
'-i',
containerID,
'php',
'-f',
'occ',
'user:add-app-password',
username!,
],
stdin: inputStream.stream,
);
inputStream.add(utf8.encode(password!));
await inputStream.close();
final result = await process;
if (result.exitCode != 0) {
throw Exception('Failed to run generate app password command\n${result.stderr}\n${result.stdout}');
}
clientPassword = (result.stdout as String).split('\n')[1];
}
final client = TestNextcloudClient(
'http://localhost:$port',
containerID,
username: username,
password: password,
password: clientPassword,
appType: appType,
userAgentSuffix: userAgentSuffix,
);
@ -222,6 +255,9 @@ class TestDockerHelper {
generateInstallAppInstruction(app),
],
],
// Required to workaround restrictions for localhost and http only push proxies
'RUN ./occ config:system:set allow_local_remote_servers --value=true',
'RUN sed -i "s/localhost/host.docker.internal/" /usr/src/nextcloud/apps/notifications/lib/Controller/PushController.php',
'ADD overlay /usr/src/nextcloud/',
'',
];
@ -293,3 +329,11 @@ extension ListExtension on List {
extension MapExtension on Map<String, dynamic> {
Map removeNulls() => removeNullsFromMap(this);
}
int randomPort() => 1024 + Random().nextInt(65535 - 1024);
void expectDateInReasonableTimeRange(final DateTime actual, final DateTime expected) {
const duration = Duration(seconds: 5);
expect(actual.isAfter(expected.subtract(duration)), isTrue);
expect(actual.isBefore(expected.add(duration)), isTrue);
}

220
packages/nextcloud/test/notifications_test.dart

@ -0,0 +1,220 @@
import 'dart:async';
import 'package:nextcloud/nextcloud.dart';
import 'package:nextcloud_push_proxy/nextcloud_push_proxy.dart';
import 'package:test/test.dart';
import 'helper.dart';
Future main() async {
final dockerImageName = await TestHelper.prepareDockerImage();
group('notifications', () {
late TestNextcloudClient client;
setUp(() async {
client = await TestHelper.getPreparedClient(
dockerImageName,
username: 'admin',
);
});
tearDown(() => client.destroy());
Future sendTestNotification() async {
await validateResponse<EmptyResponse, void>(
client.notifications,
client.notifications.sendAdminNotificationWithHttpInfo(
'admin',
AdminNotification(
shortMessage: '123',
longMessage: '456',
),
),
);
}
test('Send admin notification', () async {
await sendTestNotification();
});
test('List notifications', () async {
await sendTestNotification();
final startTime = DateTime.now().toUtc();
final response = (await validateResponse<ListNotificationsResponse, void>(
client.notifications,
client.notifications.listNotificationsWithHttpInfo(),
))!;
expect(response.ocs!.data, hasLength(1));
expect(response.ocs!.data[0].notificationId, 1);
expect(response.ocs!.data[0].app, 'admin_notifications');
expect(response.ocs!.data[0].user, 'admin');
expectDateInReasonableTimeRange(DateTime.parse(response.ocs!.data[0].datetime!), startTime);
expect(response.ocs!.data[0].objectType, 'admin_notifications');
expect(response.ocs!.data[0].objectId, isNotNull);
expect(response.ocs!.data[0].subject, '123');
expect(response.ocs!.data[0].message, '456');
expect(response.ocs!.data[0].link, '');
expect(response.ocs!.data[0].subjectRich, '');
expect(response.ocs!.data[0].subjectRichParameters, hasLength(0));
expect(response.ocs!.data[0].messageRich, '');
expect(response.ocs!.data[0].messageRichParameters, hasLength(0));
expect(response.ocs!.data[0].icon, isNotEmpty);
expect(response.ocs!.data[0].actions, hasLength(0));
});
test('Get notification', () async {
await sendTestNotification();
final startTime = DateTime.now().toUtc();
final response = (await validateResponse<GetNotificationResponse, void>(
client.notifications,
client.notifications.getNotificationWithHttpInfo(1),
))!;
expect(response.ocs!.data!.notificationId, 1);
expect(response.ocs!.data!.app, 'admin_notifications');
expect(response.ocs!.data!.user, 'admin');
expectDateInReasonableTimeRange(DateTime.parse(response.ocs!.data!.datetime!), startTime);
expect(response.ocs!.data!.objectType, 'admin_notifications');
expect(response.ocs!.data!.objectId, isNotNull);
expect(response.ocs!.data!.subject, '123');
expect(response.ocs!.data!.message, '456');
expect(response.ocs!.data!.link, '');
expect(response.ocs!.data!.subjectRich, '');
expect(response.ocs!.data!.subjectRichParameters, hasLength(0));
expect(response.ocs!.data!.messageRich, '');
expect(response.ocs!.data!.messageRichParameters, hasLength(0));
expect(response.ocs!.data!.icon, isNotEmpty);
expect(response.ocs!.data!.actions, hasLength(0));
});
test('Delete notification', () async {
await sendTestNotification();
await validateResponse<EmptyResponse, void>(
client.notifications,
client.notifications.deleteNotificationWithHttpInfo(1),
);
final response = (await validateResponse<ListNotificationsResponse, void>(
client.notifications,
client.notifications.listNotificationsWithHttpInfo(),
))!;
expect(response.ocs!.data, hasLength(0));
});
test('Delete all notifications', () async {
await sendTestNotification();
await sendTestNotification();
await validateResponse<EmptyResponse, void>(
client.notifications,
client.notifications.deleteAllNotificationsWithHttpInfo(),
);
final response = (await validateResponse<ListNotificationsResponse, void>(
client.notifications,
client.notifications.listNotificationsWithHttpInfo(),
))!;
expect(response.ocs!.data, hasLength(0));
});
});
group('push notifications', () {
late TestNextcloudClient client;
setUp(() async {
client = await TestHelper.getPreparedClient(
dockerImageName,
username: 'admin',
// We need to use app passwords in order to register push devices
useAppPassword: true,
);
});
tearDown(() => client.destroy());
// The key size has to be 2048, other sizes are not accepted by Nextcloud (at the moment at least)
// ignore: avoid_redundant_argument_values
RSAKeypair generateKeypair() => RSAKeypair.fromRandom(keySize: 2048);
test('Register device and receive notification', () async {
const pushToken = '789';
final port = randomPort();
final keypair = generateKeypair();
final pushProxy = NextcloudPushProxy();
final subscription = (await client.notifications.registerDeviceAtServer(
pushToken,
keypair.publicKey,
'http://host.docker.internal:$port/',
))!
.ocs!
.data!;
expect(subscription.publicKey, hasLength(451));
RSAPublicKey.fromPEM(subscription.publicKey!);
expect(subscription.deviceIdentifier, isNotEmpty);
expect(subscription.signature, isNotEmpty);
final deviceCompleter = Completer();
final notificationCompleter = Completer();
await pushProxy.create(
logging: false,
port: port,
);
pushProxy.onNewDevice.listen((final device) async {
expect(device.pushToken, pushToken);
expect(device.deviceIdentifier, isNotEmpty);
expect(device.deviceIdentifierSignature, isNotEmpty);
expect(device.userPublicKey, isNotEmpty);
deviceCompleter.complete();
});
pushProxy.onNewNotification.listen((final notification) async {
expect(notification.deviceIdentifier, subscription.deviceIdentifier);
expect(notification.pushTokenHash, client.notifications.generatePushTokenHash(pushToken));
expect(notification.subject, isNotEmpty);
expect(notification.signature, isNotEmpty);
expect(notification.priority, 'normal');
expect(notification.type, 'alert');
final decryptedSubject =
client.notifications.decryptPushNotificationSubject(keypair.privateKey, notification.subject);
expect(decryptedSubject.nid, isNotNull);
expect(decryptedSubject.app, 'admin_notifications');
expect(decryptedSubject.subject, '123');
expect(decryptedSubject.type, 'admin_notifications');
expect(decryptedSubject.id, isNotEmpty);
notificationCompleter.complete();
});
await client.notifications.registerDeviceAtPushProxy(
pushToken,
subscription,
'http://localhost:$port/',
);
await client.notifications.sendAdminNotification(
'admin',
AdminNotification(
shortMessage: '123',
longMessage: '456',
),
);
await deviceCompleter.future;
await notificationCompleter.future;
await pushProxy.close();
});
test('Remove push device', () async {
await client.notifications.registerDeviceAtServer(
'789',
generateKeypair().publicKey,
'https://example.com/',
);
await validateResponse<EmptyResponse, void>(
client.notifications,
client.notifications.removeDeviceWithHttpInfo(),
);
});
});
}

12
packages/nextcloud/test/webdav_test.dart

@ -43,8 +43,7 @@ Future main() async {
final file = files.singleWhere((final f) => f.name == 'Nextcloud.png');
expect(file.hasPreview, isTrue);
expect(file.mimeType, 'image/png');
expect(file.lastModified!.isBefore(DateTime.now()), isTrue);
expect(file.lastModified!.isAfter(DateTime.now().subtract(const Duration(seconds: 5))), isTrue);
expectDateInReasonableTimeRange(file.lastModified!, DateTime.now());
expect(file.size!, 50598);
});
@ -154,8 +153,7 @@ Future main() async {
);
expect(file.hasPreview, isTrue);
expect(file.mimeType, 'image/png');
expect(file.lastModified!.isBefore(DateTime.now()), isTrue);
expect(file.lastModified!.isAfter(DateTime.now().subtract(const Duration(seconds: 5))), isTrue);
expectDateInReasonableTimeRange(file.lastModified!, DateTime.now());
expect(file.size!, 50598);
});
@ -176,8 +174,7 @@ Future main() async {
expect(file.isDirectory, isTrue);
expect(file.name, 'test');
expect(file.mimeType, null);
expect(file.lastModified!.isBefore(DateTime.now()), isTrue);
expect(file.lastModified!.isAfter(DateTime.now().subtract(const Duration(seconds: 5))), isTrue);
expectDateInReasonableTimeRange(file.lastModified!, DateTime.now());
expect(file.size!, data.lengthInBytes);
});
@ -225,8 +222,7 @@ Future main() async {
);
expect(file.favorite, isTrue);
expect(file.createdDate!.isAtSameMomentAs(createdDate), isTrue);
expect(file.uploadedDate!.isAfter(uploadTime), isTrue);
expect(file.uploadedDate!.isBefore(DateTime.now()), isTrue);
expectDateInReasonableTimeRange(file.uploadedDate!, uploadTime);
});
test('Set custom properties', () async {

10
packages/nextcloud_push_proxy/.gitignore vendored

@ -0,0 +1,10 @@
# Files and directories created by pub.
.dart_tool/
.packages
# Conventional directory for build outputs.
build/
# Omit committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock

12
packages/nextcloud_push_proxy/LICENSE

@ -0,0 +1,12 @@
Copyright (c) 2022, jld3103
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

5
packages/nextcloud_push_proxy/analysis_options.yaml

@ -0,0 +1,5 @@
include: package:nit_picking/dart.yaml
linter:
rules:
prefer_final_parameters: false # Disabled until super.X is no longer complained about in constructors

143
packages/nextcloud_push_proxy/lib/nextcloud_push_proxy.dart

@ -0,0 +1,143 @@
// ignore_for_file: public_member_api_docs
library nextcloud_push_proxy;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart';
import 'package:shelf_router/shelf_router.dart';
/// Implements the listening part of a Nextcloud push proxy
class NextcloudPushProxy {
HttpServer? _server;
late StreamController<PushProxyDevice> _onNewDeviceController;
late StreamController<PushProxyNotification> _onNewNotificationController;
Stream<PushProxyDevice>? _onNewDeviceStream;
Stream<PushProxyNotification>? _onNewNotificationStream;
/// Listens for new devices
Stream<PushProxyDevice> get onNewDevice {
if (_onNewDeviceStream == null) {
throw Exception('Server not created');
}
return _onNewDeviceStream!;
}
/// Listens for new notifications
Stream<PushProxyNotification> get onNewNotification {
if (_onNewNotificationStream == null) {
throw Exception('Server not created');
}
return _onNewNotificationStream!;
}
late final _router = Router()
..post('/devices', _devicesHandler)
..post('/notifications', _notificationsHandler);
Future<Response> _devicesHandler(Request request) async {
final data = Uri(query: await request.readAsString()).queryParameters;
_onNewDeviceController.add(
PushProxyDevice(
pushToken: data['pushToken']!,
deviceIdentifier: data['deviceIdentifier']!,
deviceIdentifierSignature: data['deviceIdentifierSignature']!,
userPublicKey: data['userPublicKey']!,
),
);
return Response.ok('');
}
Future<Response> _notificationsHandler(Request request) async {
final data = Uri(query: await request.readAsString()).queryParameters;
for (final notification in data.values) {
final notificationData = json.decode(notification) as Map<String, dynamic>;
_onNewNotificationController.add(
PushProxyNotification(
deviceIdentifier: notificationData['deviceIdentifier']! as String,
pushTokenHash: notificationData['pushTokenHash']! as String,
subject: notificationData['subject']! as String,
signature: notificationData['signature']! as String,
priority: notificationData['priority']! as String,
type: notificationData['type']! as String,
),
);
}
return Response.ok('');
}
/// Creates a server listening on the [port]
Future create({
final bool logging = true,
final int port = 8080,
}) async {
if (_server != null) {
throw Exception('Server already created');
}
_onNewDeviceController = StreamController<PushProxyDevice>();
_onNewNotificationController = StreamController<PushProxyNotification>();
_onNewDeviceStream = _onNewDeviceController.stream.asBroadcastStream();
_onNewNotificationStream = _onNewNotificationController.stream.asBroadcastStream();
var handler = Cascade().add(_router).handler;
if (logging) {
handler = logRequests().addHandler(handler);
}
final server = await serve(
handler,
InternetAddress.anyIPv4,
port,
);
server.autoCompress = true;
_server = server;
}
/// Closes the server
Future close() async {
if (_server != null) {
await _server!.close();
_server = null;
await _onNewDeviceController.close();
await _onNewNotificationController.close();
}
}
}
class PushProxyDevice {
PushProxyDevice({
required this.pushToken,
required this.deviceIdentifier,
required this.deviceIdentifierSignature,
required this.userPublicKey,
});
final String pushToken;
final String deviceIdentifier;
final String deviceIdentifierSignature;
final String userPublicKey;
}
class PushProxyNotification {
PushProxyNotification({
required this.deviceIdentifier,
required this.pushTokenHash,
required this.subject,
required this.signature,
required this.priority,
required this.type,
});
final String deviceIdentifier;
final String pushTokenHash;
final String subject;
final String signature;
final String priority;
final String type;
}

7
packages/nextcloud_push_proxy/mono_pkg.yaml

@ -0,0 +1,7 @@
sdk:
- stable
stages:
- analyze:
- analyze
- format: --output=none --set-exit-if-changed --line-length 120 .

15
packages/nextcloud_push_proxy/pubspec.yaml

@ -0,0 +1,15 @@
name: nextcloud_push_proxy
version: 1.0.0
environment:
sdk: '>=2.17.0 <3.0.0'
dependencies:
shelf: ^1.3.1
shelf_router: ^1.1.3
dev_dependencies:
nit_picking:
git:
url: https://github.com/stack11/dart_nit_picking
ref: f29382f

389
specs/notifications.json

@ -0,0 +1,389 @@
{
"openapi": "3.0.3",
"info": {
"title": "Notifications",
"version": "2.12.0",
"description": "This app provides a backend and frontend for the notification API available in Nextcloud.",
"license": {
"name": "agpl"
}
},
"servers": [
{
"url": "https://{hostname}:{port}/ocs/v1.php/apps/notifications",
"variables": {
"hostname": {
"default": "localhost"
},
"port": {
"default": "8080"
}
}
}
],
"security": [
{
"basic_auth": []
}
],
"components": {
"securitySchemes": {
"basic_auth": {
"type": "http",
"scheme": "basic"
}
},
"schemas": {
"OCSMeta": {
"deprecated": true,
"description": "Stub"
},
"AdminNotification": {
"type": "object",
"properties": {
"shortMessage": {
"type": "string"
},
"longMessage": {
"type": "string"
}
}
},
"EmptyResponse": {
"type": "object",
"properties": {
"ocs": {
"type": "object",
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"Notification": {
"type": "object",
"properties": {
"notification_id": {
"type": "integer"
},
"app": {
"type": "string"
},
"user": {
"type": "string"
},
"datetime": {
"type": "string"
},
"object_type": {
"type": "string"
},
"object_id": {
"type": "string"
},
"subject": {
"type": "string"
},
"message": {
"type": "string"
},
"link": {
"type": "string"
},
"subjectRich": {
"type": "string"
},
"subjectRichParameters": {
"type": "array",
"items": {
"description": "TODO",
"type": "string"
}
},
"messageRich": {
"type": "string"
},
"messageRichParameters": {
"type": "array",
"items": {
"description": "TODO",
"type": "string"
}
},
"icon": {
"type": "string"
},
"actions": {
"type": "array",
"items": {
"description": "TODO",
"type": "string"
}
}
}
},
"ListNotificationsResponse": {
"type": "object",
"properties": {
"ocs": {
"type": "object",
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Notification"
}
}
}
}
}
},
"GetNotificationResponse": {
"type": "object",
"properties": {
"ocs": {
"type": "object",
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"$ref": "#/components/schemas/Notification"
}
}
}
}
},
"PushServerDevice": {
"type": "object",
"properties": {
"pushTokenHash": {
"type": "string"
},
"devicePublicKey": {
"type": "string"
},
"proxyServer": {
"type": "string"
}
}
},
"PushServerSubscription": {
"type": "object",
"properties": {
"publicKey": {
"type": "string"
},
"deviceIdentifier": {
"type": "string"
},
"signature": {
"type": "string"
}
}
},
"PushServerRegistrationResponse": {
"type": "object",
"properties": {
"ocs": {
"type": "object",
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"$ref": "#/components/schemas/PushServerSubscription"
}
}
}
}
},
"PushNotificationDecryptedSubject": {
"type": "object",
"properties": {
"nid": {
"type": "integer"
},
"app": {
"type": "string"
},
"subject": {
"type": "string"
},
"type": {
"type": "string"
},
"id": {
"type": "string"
}
}
}
}
},
"paths": {
"/api/v2/notifications": {
"get": {
"operationId": "list-notifications",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
},
"delete": {
"operationId": "delete-all-notifications",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/api/v2/notifications/{id}": {
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
}
}
],
"get": {
"operationId": "get-notification",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetNotificationResponse"
}
}
}
}
}
},
"delete": {
"operationId": "delete-notification",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EmptyResponse"
}
}
}
}
}
}
},
"/api/v2/push": {
"post": {
"operationId": "register-device",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PushServerDevice"
}
}
}
},
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PushServerRegistrationResponse"
}
}
}
}
}
},
"delete": {
"operationId": "remove-device",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/api/v2/admin_notifications/{userId}": {
"parameters": [
{
"name": "userId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"post": {
"operationId": "send-admin-notification",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdminNotification"
}
}
}
},
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EmptyResponse"
}
}
}
}
}
}
}
}
}

235
specs/templates/notifications.json

@ -0,0 +1,235 @@
{
"openapi": "3.0.3",
"info": {
"title": "Notifications",
"version": "2.12.0",
"description": "This app provides a backend and frontend for the notification API available in Nextcloud.",
"license": {
"name": "agpl"
}
},
"servers": [
{
"url": "https://{hostname}:{port}/ocs/v1.php/apps/notifications",
"variables": {
"hostname": {
"default": "localhost"
},
"port": {
"default": "8080"
}
}
}
],
"security": [
{
"basic_auth": []
}
],
"components": {
"securitySchemes": {
"basic_auth": {
"type": "http",
"scheme": "basic"
}
}
},
"paths": {
"/api/{apiVersion}/notifications": {
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"get": {
"operationId": "endpoint-listnotifications-TODO",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
},
"delete": {
"operationId": "endpoint-deleteallnotifications-TODO",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/api/{apiVersion}/notifications/{id}": {
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer"
}
}
],
"get": {
"operationId": "endpoint-getnotification-TODO",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
},
"delete": {
"operationId": "endpoint-deletenotification-TODO",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/api/{apiVersion}/push": {
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "TODO"
}
}
],
"post": {
"operationId": "push-registerdevice-TODO",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
},
"delete": {
"operationId": "push-removedevice-TODO",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/api/{apiVersion}/admin_notifications/{userId}": {
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "TODO"
}
},
{
"name": "userId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"post": {
"operationId": "api-generatenotification-TODO",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/api/{apiVersion}/settings": {
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "TODO"
}
}
],
"post": {
"operationId": "settings-personal-TODO",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
}
}
}

2
tool/generate-nextcloud.sh

@ -99,6 +99,7 @@ mkdir -p /tmp/nextcloud-harbour
spec_templates_generate external/nextcloud-news false
spec_templates_generate external/nextcloud-notes false
spec_templates_generate external/nextcloud-notifications false
spec_templates_generate external/nextcloud-server/apps/provisioning_api false
spec_templates_generate external/nextcloud-server/apps/user_status false
spec_templates_generate external/nextcloud-server/core true
@ -107,6 +108,7 @@ openapi_generate "common" true
openapi_generate "core" false
openapi_generate "news" false
openapi_generate "notes" false
openapi_generate "notifications" false
openapi_generate "provisioning_api" false
openapi_generate "user_status" false

Loading…
Cancel
Save