diff --git a/generate.sh b/generate.sh index baa55ac..10af42d 100755 --- a/generate.sh +++ b/generate.sh @@ -27,7 +27,7 @@ echo "Applying PHP-specific fixes..." sed -i '' '/public ?string $role = null,/{N;s/public ?string $role = null,\n public ?string $role = null,/public ?string $role = null,/;}' src/GeneratedModels/CallParticipant.php # Fix queryUsers method to use proper namespace and required parameter -sed -i '' 's/QueryUsersPayload \$payload/GeneratedModels\\QueryUsersPayload \$payload/' src/Generated/CommonClient.php +sed -i '' 's/QueryUsersPayload \$payload/GeneratedModels\\QueryUsersPayload \$payload/' src/Generated/CommonTrait.php # Run PHP CS Fixer to ensure code style compliance if [ -f ".php-cs-fixer.php" ]; then diff --git a/src/Client.php b/src/Client.php index 8acf69c..5fb305c 100644 --- a/src/Client.php +++ b/src/Client.php @@ -8,14 +8,14 @@ use GetStream\Http\HttpClientInterface; use GetStream\Http\GuzzleHttpClient; use GetStream\Auth\JWTGenerator; -use GetStream\Generated\CommonClient; +use GetStream\Generated\CommonTrait; /** * Main GetStream client for interacting with the API */ class Client { - use CommonClient; + use CommonTrait; private string $apiKey; private string $apiSecret; private string $baseUrl; diff --git a/src/ClientBuilder.php b/src/ClientBuilder.php index 7e200fe..0e740e2 100644 --- a/src/ClientBuilder.php +++ b/src/ClientBuilder.php @@ -104,6 +104,15 @@ public function buildFeedsClient(): FeedsV3Client{ return new FeedsV3Client($this->apiKey, $this->apiSecret, $this->baseUrl, $this->httpClient); } +/** + * @throws StreamException + */ + public function buildModerationClient(): ModerationClient{ + $this->loadCreds(); + return new ModerationClient($this->apiKey, $this->apiSecret, $this->baseUrl, $this->httpClient); + } + + public function loadCreds(): void { // Load environment variables if enabled diff --git a/src/FeedsV3Client.php b/src/FeedsV3Client.php index 89712c1..8be5507 100644 --- a/src/FeedsV3Client.php +++ b/src/FeedsV3Client.php @@ -2,14 +2,14 @@ namespace GetStream; -use GetStream\Generated\FeedsClient; +use GetStream\Generated\FeedsTrait; class FeedsV3Client extends Client { // function __construct(Client $client){ // parent::__construct($client); // } - use FeedsClient; + use FeedsTrait; } diff --git a/src/Generated/CommonClient.php b/src/Generated/CommonTrait.php similarity index 94% rename from src/Generated/CommonClient.php rename to src/Generated/CommonTrait.php index c4573d6..160ee09 100644 --- a/src/Generated/CommonClient.php +++ b/src/Generated/CommonTrait.php @@ -12,7 +12,7 @@ * This trait contains auto-generated methods from the OpenAPI specification. * Include this trait in your Client class to add these methods. */ -trait CommonClient +trait CommonTrait { /** * This Method returns the application settings @@ -682,6 +682,21 @@ public function queryPollVotes(string $pollID, string $userID, GeneratedModels\Q // Use the provided request data array directly return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\PollVotesResponse::class); } + /** + * Upserts the push preferences for a user and or channel member. Set to all, mentions or none + * + * + * @param GeneratedModels\UpsertPushPreferencesRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function updatePushNotificationPreferences(GeneratedModels\UpsertPushPreferencesRequest $requestData): StreamResponse { + $path = '/api/v2/push_preferences'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\UpsertPushPreferencesResponse::class); + } /** * List details of all push providers. * @@ -729,6 +744,43 @@ public function deletePushProvider(string $type, string $name): StreamResponse { $requestData = null; return StreamResponse::fromJson($this->makeRequest('DELETE', $path, $queryParams, $requestData), GeneratedModels\Response::class); } + /** + * Retrieve push notification templates for Chat. + * + * + * @param string $pushProviderType + * @param string $pushProviderName + * @return StreamResponse + * @throws StreamException + */ + public function getPushTemplates(string $pushProviderType, string $pushProviderName): StreamResponse { + $path = '/api/v2/push_templates'; + + $queryParams = []; + if ($pushProviderType !== null) { + $queryParams['push_provider_type'] = $pushProviderType; + } + if ($pushProviderName !== null) { + $queryParams['push_provider_name'] = $pushProviderName; + } + $requestData = null; + return StreamResponse::fromJson($this->makeRequest('GET', $path, $queryParams, $requestData), GeneratedModels\GetPushTemplatesResponse::class); + } + /** + * Create or update a push notification template for a specific event type and push provider + * + * + * @param GeneratedModels\UpsertPushTemplateRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function upsertPushTemplate(GeneratedModels\UpsertPushTemplateRequest $requestData): StreamResponse { + $path = '/api/v2/push_templates'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\UpsertPushTemplateResponse::class); + } /** * Get rate limits usage and quotas * diff --git a/src/Generated/FeedsClient.php b/src/Generated/FeedsTrait.php similarity index 97% rename from src/Generated/FeedsClient.php rename to src/Generated/FeedsTrait.php index 0f3bb7b..c6d734a 100644 --- a/src/Generated/FeedsClient.php +++ b/src/Generated/FeedsTrait.php @@ -12,7 +12,7 @@ * This trait contains auto-generated methods from the OpenAPI specification. * Include this trait in your Client class to add these methods. */ -trait FeedsClient +trait FeedsTrait { /** * Create a new activity or update an existing one @@ -1057,6 +1057,36 @@ public function updateFeedView(string $id, GeneratedModels\UpdateFeedViewRequest // Use the provided request data array directly return StreamResponse::fromJson($this->makeRequest('PUT', $path, $queryParams, $requestData), GeneratedModels\UpdateFeedViewResponse::class); } + /** + * Gets all available feed visibility configurations and their permissions + * + * + * @return StreamResponse + * @throws StreamException + */ + public function listFeedVisibilities(): StreamResponse { + $path = '/api/v2/feeds/feed_visibilities'; + + $queryParams = []; + $requestData = null; + return StreamResponse::fromJson($this->makeRequest('GET', $path, $queryParams, $requestData), GeneratedModels\ListFeedVisibilitiesResponse::class); + } + /** + * Gets feed visibility configuration and permissions + * + * + * @param string $name + * @return StreamResponse + * @throws StreamException + */ + public function getFeedVisibility(string $name): StreamResponse { + $path = '/api/v2/feeds/feed_visibilities/{name}'; + $path = str_replace('{name}', (string) $name, $path); + + $queryParams = []; + $requestData = null; + return StreamResponse::fromJson($this->makeRequest('GET', $path, $queryParams, $requestData), GeneratedModels\GetFeedVisibilityResponse::class); + } /** * Create multiple feeds at once for a given feed group * @@ -1088,7 +1118,7 @@ public function queryFeeds(GeneratedModels\QueryFeedsRequest $requestData): Stre return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\QueryFeedsResponse::class); } /** - * Updates a follow's custom data, push preference, and follower role. Source owner can update custom data and push preference. Target owner can update follower role. + * Updates a follow's custom data, push preference, and follower role. Source owner can update custom data and push preference. Follower role can only be updated via server-side requests. * * * @param GeneratedModels\UpdateFollowRequest $requestData diff --git a/src/Generated/ModerationTrait.php b/src/Generated/ModerationTrait.php new file mode 100644 index 0000000..9294764 --- /dev/null +++ b/src/Generated/ModerationTrait.php @@ -0,0 +1,396 @@ + + * @throws StreamException + */ + public function ban(GeneratedModels\BanRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/ban'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\BanResponse::class); + } + /** + * Moderate multiple images in bulk using a CSV file + * + * + * @param GeneratedModels\BulkImageModerationRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function bulkImageModeration(GeneratedModels\BulkImageModerationRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/bulk_image_moderation'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\BulkImageModerationResponse::class); + } + /** + * Run moderation checks on the provided content + * + * + * @param GeneratedModels\CheckRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function check(GeneratedModels\CheckRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/check'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\CheckResponse::class); + } + /** + * Create a new moderation configuration or update an existing one. Configure settings for content filtering, AI analysis, toxicity detection, and other moderation features. + * + * + * @param GeneratedModels\UpsertConfigRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function upsertConfig(GeneratedModels\UpsertConfigRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/config'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\UpsertConfigResponse::class); + } + /** + * Delete a specific moderation policy by its name + * + * + * @param string $key + * @param string $team + * @return StreamResponse + * @throws StreamException + */ + public function deleteConfig(string $key, string $team): StreamResponse { + $path = '/api/v2/moderation/config/{key}'; + $path = str_replace('{key}', (string) $key, $path); + + $queryParams = []; + if ($team !== null) { + $queryParams['team'] = $team; + } + $requestData = null; + return StreamResponse::fromJson($this->makeRequest('DELETE', $path, $queryParams, $requestData), GeneratedModels\DeleteModerationConfigResponse::class); + } + /** + * Retrieve a specific moderation configuration by its key and team. This configuration contains settings for various moderation features like toxicity detection, AI analysis, and filtering rules. + * + * + * @param string $key + * @param string $team + * @return StreamResponse + * @throws StreamException + */ + public function getConfig(string $key, string $team): StreamResponse { + $path = '/api/v2/moderation/config/{key}'; + $path = str_replace('{key}', (string) $key, $path); + + $queryParams = []; + if ($team !== null) { + $queryParams['team'] = $team; + } + $requestData = null; + return StreamResponse::fromJson($this->makeRequest('GET', $path, $queryParams, $requestData), GeneratedModels\GetConfigResponse::class); + } + /** + * Search and filter moderation configurations across your application. This endpoint is designed for building moderation dashboards and managing multiple configuration sets. + * + * + * @param GeneratedModels\QueryModerationConfigsRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function queryModerationConfigs(GeneratedModels\QueryModerationConfigsRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/configs'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\QueryModerationConfigsResponse::class); + } + /** + * Custom check, add your own AI model reports to the review queue + * + * + * @param GeneratedModels\CustomCheckRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function customCheck(GeneratedModels\CustomCheckRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/custom_check'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\CustomCheckResponse::class); + } + /** + * Delete a specific moderation template by its name + * + * + * @return StreamResponse + * @throws StreamException + */ + public function v2DeleteTemplate(): StreamResponse { + $path = '/api/v2/moderation/feeds_moderation_template'; + + $queryParams = []; + $requestData = null; + return StreamResponse::fromJson($this->makeRequest('DELETE', $path, $queryParams, $requestData), GeneratedModels\DeleteModerationTemplateResponse::class); + } + /** + * Retrieve a list of feed moderation templates that define preset moderation rules and configurations. Limited to 100 templates per request. + * + * + * @return StreamResponse + * @throws StreamException + */ + public function v2QueryTemplates(): StreamResponse { + $path = '/api/v2/moderation/feeds_moderation_template'; + + $queryParams = []; + $requestData = null; + return StreamResponse::fromJson($this->makeRequest('GET', $path, $queryParams, $requestData), GeneratedModels\QueryFeedModerationTemplatesResponse::class); + } + /** + * Upsert feeds template for moderation + * + * + * @param GeneratedModels\UpsertModerationTemplateRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function v2UpsertTemplate(GeneratedModels\UpsertModerationTemplateRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/feeds_moderation_template'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\UpsertModerationTemplateResponse::class); + } + /** + * Flag any type of content (messages, users, channels, activities) for moderation review. Supports custom content types and additional metadata for flagged content. + * + * + * @param GeneratedModels\FlagRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function flag(GeneratedModels\FlagRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/flag'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\FlagResponse::class); + } + /** + * Query flags associated with moderation items. This is used for building a moderation dashboard. + * + * + * @param GeneratedModels\QueryModerationFlagsRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function queryModerationFlags(GeneratedModels\QueryModerationFlagsRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/flags'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\QueryModerationFlagsResponse::class); + } + /** + * Search and filter moderation action logs with support for pagination. View the history of moderation actions taken, including who performed them and when. + * + * + * @param GeneratedModels\QueryModerationLogsRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function queryModerationLogs(GeneratedModels\QueryModerationLogsRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/logs'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\QueryModerationLogsResponse::class); + } + /** + * Create or update a moderation rule that can apply app-wide or to specific moderation configs + * + * + * @param GeneratedModels\UpsertModerationRuleRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function upsertModerationRule(GeneratedModels\UpsertModerationRuleRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/moderation_rule'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\UpsertModerationRuleResponse::class); + } + /** + * Delete an existing moderation rule + * + * + * @return StreamResponse + * @throws StreamException + */ + public function deleteModerationRule(): StreamResponse { + $path = '/api/v2/moderation/moderation_rule/{id}'; + + $queryParams = []; + $requestData = null; + return StreamResponse::fromJson($this->makeRequest('DELETE', $path, $queryParams, $requestData), GeneratedModels\DeleteModerationRuleResponse::class); + } + /** + * Get a specific moderation rule by ID + * + * + * @return StreamResponse + * @throws StreamException + */ + public function getModerationRule(): StreamResponse { + $path = '/api/v2/moderation/moderation_rule/{id}'; + + $queryParams = []; + $requestData = null; + return StreamResponse::fromJson($this->makeRequest('GET', $path, $queryParams, $requestData), GeneratedModels\GetModerationRuleResponse::class); + } + /** + * Search and filter moderation rules across your application. This endpoint is designed for building moderation dashboards and managing multiple rule sets. + * + * + * @param GeneratedModels\QueryModerationRulesRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function queryModerationRules(GeneratedModels\QueryModerationRulesRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/moderation_rules'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\QueryModerationRulesResponse::class); + } + /** + * Mute a user. Mutes are generally not visible to the user you mute, while block is something you notice. + * + * + * @param GeneratedModels\MuteRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function mute(GeneratedModels\MuteRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/mute'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\MuteResponse::class); + } + /** + * Query review queue items allows you to filter the review queue items. This is used for building a moderation dashboard. + * + * + * @param GeneratedModels\QueryReviewQueueRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function queryReviewQueue(GeneratedModels\QueryReviewQueueRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/review_queue'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\QueryReviewQueueResponse::class); + } + /** + * Retrieve a specific review queue item by its ID + * + * + * @param string $id + * @return StreamResponse + * @throws StreamException + */ + public function getReviewQueueItem(string $id): StreamResponse { + $path = '/api/v2/moderation/review_queue/{id}'; + $path = str_replace('{id}', (string) $id, $path); + + $queryParams = []; + $requestData = null; + return StreamResponse::fromJson($this->makeRequest('GET', $path, $queryParams, $requestData), GeneratedModels\GetReviewQueueItemResponse::class); + } + /** + * Take action on flagged content, such as marking content as safe, deleting content, banning users, or executing custom moderation actions. Supports various action types with configurable parameters. + * + * + * @param GeneratedModels\SubmitActionRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function submitAction(GeneratedModels\SubmitActionRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/submit_action'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\SubmitActionResponse::class); + } + /** + * Unban a user from a channel or globally. + * + * + * @param string $targetUserID + * @param string $channelCid + * @param string $createdBy + * @param GeneratedModels\UnbanRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function unban(string $targetUserID, string $channelCid, string $createdBy, GeneratedModels\UnbanRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/unban'; + + $queryParams = []; + if ($targetUserID !== null) { + $queryParams['target_user_id'] = $targetUserID; + } + if ($channelCid !== null) { + $queryParams['channel_cid'] = $channelCid; + } + if ($createdBy !== null) { + $queryParams['created_by'] = $createdBy; + } + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\UnbanResponse::class); + } + /** + * Unmute a user + * + * + * @param GeneratedModels\UnmuteRequest $requestData + * @return StreamResponse + * @throws StreamException + */ + public function unmute(GeneratedModels\UnmuteRequest $requestData): StreamResponse { + $path = '/api/v2/moderation/unmute'; + + $queryParams = []; + // Use the provided request data array directly + return StreamResponse::fromJson($this->makeRequest('POST', $path, $queryParams, $requestData), GeneratedModels\UnmuteResponse::class); + } +} diff --git a/src/GeneratedModels/AIImageConfig.php b/src/GeneratedModels/AIImageConfig.php index e58cc4f..3b94888 100644 --- a/src/GeneratedModels/AIImageConfig.php +++ b/src/GeneratedModels/AIImageConfig.php @@ -11,10 +11,10 @@ class AIImageConfig extends BaseModel { public function __construct( + public ?bool $async = null, public ?bool $enabled = null, public ?array $ocrRules = null, public ?array $rules = null, - public ?bool $async = null, ) {} // BaseModel automatically handles jsonSerialize(), toArray(), and fromJson() using constructor types! diff --git a/src/GeneratedModels/AITextConfig.php b/src/GeneratedModels/AITextConfig.php index c25207e..ecafecc 100644 --- a/src/GeneratedModels/AITextConfig.php +++ b/src/GeneratedModels/AITextConfig.php @@ -11,11 +11,11 @@ class AITextConfig extends BaseModel { public function __construct( + public ?bool $async = null, public ?bool $enabled = null, public ?string $profile = null, public ?array $rules = null, public ?array $severityRules = null, - public ?bool $async = null, ) {} // BaseModel automatically handles jsonSerialize(), toArray(), and fromJson() using constructor types! diff --git a/src/GeneratedModels/AIVideoConfig.php b/src/GeneratedModels/AIVideoConfig.php index 84ea413..c37e3fe 100644 --- a/src/GeneratedModels/AIVideoConfig.php +++ b/src/GeneratedModels/AIVideoConfig.php @@ -11,9 +11,9 @@ class AIVideoConfig extends BaseModel { public function __construct( + public ?bool $async = null, public ?bool $enabled = null, public ?array $rules = null, - public ?bool $async = null, ) {} // BaseModel automatically handles jsonSerialize(), toArray(), and fromJson() using constructor types! diff --git a/src/GeneratedModels/ActivityResponse.php b/src/GeneratedModels/ActivityResponse.php index 3f61db6..6de6684 100644 --- a/src/GeneratedModels/ActivityResponse.php +++ b/src/GeneratedModels/ActivityResponse.php @@ -44,7 +44,7 @@ public function __construct( public ?FeedResponse $currentFeed = null, public ?ActivityLocation $location = null, public ?ModerationV2Response $moderation = null, - public ?object $notificationContext = null, // Notification context data for the activity (if this is a reaction, comment, follow, etc.) + public ?NotificationContext $notificationContext = null, public ?ActivityResponse $parent = null, public ?PollResponseData $poll = null, ) {} diff --git a/src/GeneratedModels/AggregatedActivityResponse.php b/src/GeneratedModels/AggregatedActivityResponse.php index d25c56a..305efa4 100644 --- a/src/GeneratedModels/AggregatedActivityResponse.php +++ b/src/GeneratedModels/AggregatedActivityResponse.php @@ -17,6 +17,7 @@ public function __construct( public ?int $score = null, // Ranking score for this aggregation public ?\DateTime $updatedAt = null, // When the aggregation was last updated public ?int $userCount = null, // Number of unique users in this aggregation + public ?bool $userCountTruncated = null, // Whether this activity group has been truncated due to exceeding the group size limit public ?array $activities = null, // List of activities in this aggregation ) {} diff --git a/src/GeneratedModels/AutomodPlatformCircumventionConfig.php b/src/GeneratedModels/AutomodPlatformCircumventionConfig.php index f35d519..ebbeaf0 100644 --- a/src/GeneratedModels/AutomodPlatformCircumventionConfig.php +++ b/src/GeneratedModels/AutomodPlatformCircumventionConfig.php @@ -11,9 +11,9 @@ class AutomodPlatformCircumventionConfig extends BaseModel { public function __construct( + public ?bool $async = null, public ?bool $enabled = null, public ?array $rules = null, - public ?bool $async = null, ) {} // BaseModel automatically handles jsonSerialize(), toArray(), and fromJson() using constructor types! diff --git a/src/GeneratedModels/AutomodSemanticFiltersConfig.php b/src/GeneratedModels/AutomodSemanticFiltersConfig.php index f6560e5..a1352e5 100644 --- a/src/GeneratedModels/AutomodSemanticFiltersConfig.php +++ b/src/GeneratedModels/AutomodSemanticFiltersConfig.php @@ -11,9 +11,9 @@ class AutomodSemanticFiltersConfig extends BaseModel { public function __construct( + public ?bool $async = null, public ?bool $enabled = null, public ?array $rules = null, - public ?bool $async = null, ) {} // BaseModel automatically handles jsonSerialize(), toArray(), and fromJson() using constructor types! diff --git a/src/GeneratedModels/AutomodToxicityConfig.php b/src/GeneratedModels/AutomodToxicityConfig.php index a401b2f..1eb396c 100644 --- a/src/GeneratedModels/AutomodToxicityConfig.php +++ b/src/GeneratedModels/AutomodToxicityConfig.php @@ -11,9 +11,9 @@ class AutomodToxicityConfig extends BaseModel { public function __construct( + public ?bool $async = null, public ?bool $enabled = null, public ?array $rules = null, - public ?bool $async = null, ) {} // BaseModel automatically handles jsonSerialize(), toArray(), and fromJson() using constructor types! diff --git a/src/GeneratedModels/BanOptions.php b/src/GeneratedModels/BanOptions.php index c38c3de..7e6e03e 100644 --- a/src/GeneratedModels/BanOptions.php +++ b/src/GeneratedModels/BanOptions.php @@ -11,6 +11,7 @@ class BanOptions extends BaseModel { public function __construct( + public ?string $deleteMessages = null, public ?int $duration = null, public ?bool $ipBan = null, public ?string $reason = null, diff --git a/src/GeneratedModels/BlockListConfig.php b/src/GeneratedModels/BlockListConfig.php index caffb68..7511754 100644 --- a/src/GeneratedModels/BlockListConfig.php +++ b/src/GeneratedModels/BlockListConfig.php @@ -11,9 +11,9 @@ class BlockListConfig extends BaseModel { public function __construct( + public ?bool $async = null, public ?bool $enabled = null, public ?array $rules = null, - public ?bool $async = null, ) {} // BaseModel automatically handles jsonSerialize(), toArray(), and fromJson() using constructor types! diff --git a/src/GeneratedModels/BodyguardImageAnalysisConfig.php b/src/GeneratedModels/BodyguardImageAnalysisConfig.php new file mode 100644 index 0000000..0ee66ba --- /dev/null +++ b/src/GeneratedModels/BodyguardImageAnalysisConfig.php @@ -0,0 +1,19 @@ + 'post', 'text' => 'Batch activity 1', 'user_id' => $this->testUserId, + 'feeds' => [$this->testFeed->getFeedIdentifier()], ], [ 'type' => 'post', 'text' => 'Batch activity 2', 'user_id' => $this->testUserId, + 'feeds' => [$this->testFeed->getFeedIdentifier()], ] ]; @@ -1254,8 +1256,8 @@ public function test26_ModerateActivity(): void $moderationResponse = $this->feedsV3Client->activityFeedback( $activityId, new GeneratedModels\ActivityFeedbackRequest( - report: true, reason: 'inappropriate_content', + report: true, userID: $this->testUserId2 // Different user reporting ) ); @@ -1275,7 +1277,7 @@ public function test26_ModerateActivity(): void public function test27_DeviceManagement(): void { //skip this test - $this->markTestSkipped("fix me") + $this->markTestSkipped("fix me"); echo "\n๐Ÿ“ฑ Testing device management...\n"; $deviceToken = 'test-device-token-' . uniqid(); @@ -1655,7 +1657,7 @@ public function test33_FeedGroupCRUD(): void id: $feedGroupId, defaultVisibility: 'public', activityProcessors: [ - ['type' => 'default'] + ['type' => 'dummy'] ] ) ); @@ -1668,17 +1670,17 @@ public function test33_FeedGroupCRUD(): void // Test 3: Get Feed Group echo "\n๐Ÿ” Testing get feed group...\n"; // snippet-start: GetFeedGroup - $getResponse = $this->feedsV3Client->getFeedGroup('feed_group_id'); + $getResponse = $this->feedsV3Client->getFeedGroup('foryou'); // snippet-end: GetFeedGroup $this->assertResponseSuccess($getResponse, 'get feed group'); - $this->assertEquals('feed_group_id', $getResponse->getData()->feedGroup->id); + $this->assertEquals('foryou', $getResponse->getData()->feedGroup->id); echo "โœ… Retrieved feed group: $feedGroupId\n"; // Test 4: Update Feed Group echo "\nโœ๏ธ Testing update feed group...\n"; // snippet-start: UpdateFeedGroup - $updateResponse = $this->feedsV3Client->updateFeedGroup('feed_group_id', new GeneratedModels\UpdateFeedGroupRequest( + $updateResponse = $this->feedsV3Client->updateFeedGroup('foryou', new GeneratedModels\UpdateFeedGroupRequest( aggregation: new GeneratedModels\AggregationConfig('default') )); // snippet-end: UpdateFeedGroup @@ -1689,7 +1691,7 @@ public function test33_FeedGroupCRUD(): void // Test 5: Get or Create Feed Group (should get existing) echo "\n๐Ÿ”„ Testing get or create feed group (existing)...\n"; // snippet-start: GetOrCreateFeedGroupExisting - $getOrCreateResponse = $this->feedsV3Client->getOrCreateFeedGroup('feed_group_id', new GeneratedModels\GetOrCreateFeedGroupRequest + $getOrCreateResponse = $this->feedsV3Client->getOrCreateFeedGroup('foryou', new GeneratedModels\GetOrCreateFeedGroupRequest ( defaultVisibility: 'public', )); @@ -1717,7 +1719,7 @@ public function test33_FeedGroupCRUD(): void id: $group, defaultVisibility: 'public', activityProcessors: [ - ['type' => 'default'] + ['type' => 'dummy'] ], aggregation: new GeneratedModels\AggregationConfig('{{ type }}-{{ time.strftime("%Y-%m-%d") }}') ) @@ -1734,7 +1736,7 @@ public function test33_FeedGroupCRUD(): void id: $ranked_group, defaultVisibility: 'public', ranking: new GeneratedModels\RankingConfig( - type: 'default', + type: 'recency', score: 'decay_linear(time) * popularity' ) ) @@ -1747,6 +1749,8 @@ public function test33_FeedGroupCRUD(): void */ public function test34_FeedViewCRUD(): void { + $this->markTestSkipped('Backend issue FEEDS-799'); + echo "\n๐Ÿ‘๏ธ Testing Feed View CRUD operations...\n"; $feedViewId = 'test-feed-view-' . substr(uniqid(), -8); diff --git a/tests/Integration/ModerationIntegrationTest.php b/tests/Integration/ModerationIntegrationTest.php new file mode 100644 index 0000000..630d9bc --- /dev/null +++ b/tests/Integration/ModerationIntegrationTest.php @@ -0,0 +1,420 @@ +client = ClientBuilder::fromEnv()->build(); + $this->moderationClient = ClientBuilder::fromEnv()->buildModerationClient(); + + $this->testUserId = 'test-user-' . uniqid(); + $this->testUserId2 = 'test-user-2-' . uniqid(); + $this->moderatorUserId = 'moderator-' . uniqid(); + $this->reporterUserId = 'reporter-' . uniqid(); + $this->testChannelId = 'test-channel-' . uniqid(); + $this->testChannelCid = 'messaging:' . $this->testChannelId; + + // Setup environment for each test + $this->setupEnvironment(); + } + + protected function tearDown(): void + { + // Cleanup created resources in reverse order + $this->cleanupResources(); + } + + // ================================================================= + // ENVIRONMENT SETUP (called in setUp for each test) + // ================================================================= + + private function setupEnvironment(): void + { + try { + // Create test users + // snippet-start: CreateModerationUsers + $response = $this->client->updateUsers(new GeneratedModels\UpdateUsersRequest( + users: [ + $this->testUserId => [ + 'id' => $this->testUserId, + 'name' => 'Test User 1', + 'role' => 'user' + ], + $this->testUserId2 => [ + 'id' => $this->testUserId2, + 'name' => 'Test User 2', + 'role' => 'user' + ], + $this->moderatorUserId => [ + 'id' => $this->moderatorUserId, + 'name' => 'Moderator User', + 'role' => 'admin' + ], + $this->reporterUserId => [ + 'id' => $this->reporterUserId, + 'name' => 'Reporter User', + 'role' => 'user' + ] + ] + )); + // snippet-end: CreateModerationUsers + + if (!$response->isSuccessful()) { + throw new StreamException('Failed to create users: ' . $response->getRawBody()); + } + + $this->createdUserIds = [$this->testUserId, $this->testUserId2, $this->moderatorUserId, $this->reporterUserId]; + + echo "โœ… Created test users for moderation tests\n"; + echo " Target User: {$this->testUserId}\n"; + echo " Target User 2: {$this->testUserId2}\n"; + echo " Moderator: {$this->moderatorUserId}\n"; + echo " Reporter: {$this->reporterUserId}\n"; + + } catch (StreamApiException $e) { + echo "โš ๏ธ Setup failed: " . $e->getMessage() . "\n"; + echo "ResponseBody: " . $e->getResponseBody() . "\n"; + echo "ErrorDetail: " . $e->getErrorDetails() . "\n"; + throw $e; + + } catch (\Exception $e) { + echo "โš ๏ธ Setup failed: " . $e->getMessage() . "\n"; + // Continue with tests even if setup partially fails + } + } + + // ================================================================= + // 1. ENVIRONMENT SETUP TEST (demonstrates the setup process) + // ================================================================= + + public function test01_SetupEnvironmentDemo(): void + { + echo "\n๐Ÿ”ง Demonstrating moderation environment setup...\n"; + echo "โœ… Users are automatically created in setUp()\n"; + echo " Test User 1: {$this->testUserId}\n"; + echo " Test User 2: {$this->testUserId2}\n"; + echo " Moderator: {$this->moderatorUserId}\n"; + echo " Reporter: {$this->reporterUserId}\n"; + + $this->assertTrue(true); // Just a demo test + } + + // ================================================================= + // 2. BAN/UNBAN OPERATIONS + // ================================================================= + + public function test02_BanUserWithReason(): void + { + echo "\n๐Ÿšซ Testing user ban with reason...\n"; + + // snippet-start: BanWithReason + $request = new GeneratedModels\BanRequest( + targetUserID: $this->testUserId, + reason: 'spam', + timeout: 60, // 60 minutes + bannedByID: $this->moderatorUserId + ); + + $response = $this->moderationClient->ban($request); + // snippet-stop: BanWithReason + + $this->assertResponseSuccess($response, 'ban user with reason'); + $this->bannedUserIds[] = $this->testUserId; + + echo "โœ… Successfully banned user: {$this->testUserId}\n"; + } + + public function test04_UnbanUser(): void + { + echo "\nโœ… Testing user unban...\n"; + + // First ensure user is banned + if (!in_array($this->testUserId, $this->bannedUserIds)) { + $this->test02_BanUserWithReason(); + } + + // snippet-start: UnbanUser + $request = new GeneratedModels\UnbanRequest( + unbannedByID: $this->moderatorUserId + ); + + $response = $this->moderationClient->unban($this->testUserId, '', '', $request); + // snippet-stop: UnbanUser + + $this->assertResponseSuccess($response, 'unban user'); + + // Remove from banned list + $this->bannedUserIds = array_diff($this->bannedUserIds, [$this->testUserId]); + + echo "โœ… Successfully unbanned user: {$this->testUserId}\n"; + } + + // ================================================================= + // 3. MUTE/UNMUTE OPERATIONS + // ================================================================= + + public function test05_MuteUser(): void + { + echo "\n๐Ÿ”‡ Testing user mute...\n"; + + // snippet-start: MuteUser + $request = new GeneratedModels\MuteRequest( + targetIds: [$this->testUserId2], + timeout: 30, // 30 minutes + userID: $this->moderatorUserId + ); + + $response = $this->moderationClient->mute($request); + // snippet-stop: MuteUser + + $this->assertResponseSuccess($response, 'mute user'); + $this->mutedUserIds[] = $this->testUserId2; + + echo "โœ… Successfully muted user: {$this->testUserId2}\n"; + } + + public function test06_UnmuteUser(): void + { + echo "\n๐Ÿ”Š Testing user unmute...\n"; + + // First ensure user is muted + if (!in_array($this->testUserId2, $this->mutedUserIds)) { + $this->test05_MuteUser(); + } + + // snippet-start: UnmuteUser + $request = new GeneratedModels\UnmuteRequest( + targetIds: [$this->testUserId2], + userID: $this->moderatorUserId + ); + + $response = $this->moderationClient->unmute($request); + // snippet-stop: UnmuteUser + + $this->assertResponseSuccess($response, 'unmute user'); + + // Remove from muted list + $this->mutedUserIds = array_diff($this->mutedUserIds, [$this->testUserId2]); + + echo "โœ… Successfully unmuted user: {$this->testUserId2}\n"; + } + + // ================================================================= + // 4. FLAG OPERATIONS + // ================================================================= + + public function test07_FlagUser(): void + { + echo "\n๐Ÿšฉ Testing user flagging...\n"; + + // snippet-start: FlagUser + $request = new GeneratedModels\FlagRequest( + entityType: 'user', + entityID: $this->testUserId, + entityCreatorID: $this->testUserId, + reason: 'spam', + userID: $this->reporterUserId + ); + + $response = $this->moderationClient->flag($request); + // snippet-stop: FlagUser + + $this->assertResponseSuccess($response, 'flag user'); + + echo "โœ… Successfully flagged user: {$this->testUserId}\n"; + } + + public function test12_QueryReviewQueue(): void + { + $this->markTestSkipped("backend issue"); + + echo "\n๐Ÿ“‹ Testing review queue query...\n"; + + // snippet-start: QueryReviewQueueWithFilter + $request = new GeneratedModels\QueryReviewQueueRequest( + filter: [], + limit: 25 + ); + + $response = $this->moderationClient->queryReviewQueue($request); + // snippet-stop: QueryReviewQueueWithFilter + + $this->assertResponseSuccess($response, 'query review queue'); + + echo "โœ… Successfully queried review queue\n"; + } + + // ================================================================= + // 8. QUERY OPERATIONS + // ================================================================= + + public function test13_QueryModerationFlags(): void + { + + $this->markTestSkipped("backend issue"); + + echo "\n๐Ÿšฉ Testing moderation flags query...\n"; + + // snippet-start: QueryModerationFlags + $request = new GeneratedModels\QueryModerationFlagsRequest( + filter:json_decode('{"has_text":"true"}'), + limit: 50 + ); + + $response = $this->moderationClient->queryModerationFlags($request); + // snippet-stop: QueryModerationFlags + + $this->assertResponseSuccess($response, 'query moderation flags'); + + echo "โœ… Successfully queried moderation flags\n"; + } + + public function test14_QueryModerationLogs(): void + { + $this->markTestSkipped("backend issue"); + echo "\n๐Ÿ“ Testing moderation logs query...\n"; + + // snippet-start: QueryModerationLogs + $request = new GeneratedModels\QueryModerationLogsRequest( + filter: [], + limit: 25 + ); + + $response = $this->moderationClient->queryModerationLogs($request); + // snippet-stop: QueryModerationLogs + + $this->assertResponseSuccess($response, 'query moderation logs'); + + echo "โœ… Successfully queried moderation logs\n"; + } + + // ================================================================= + // 9. TEMPLATE OPERATIONS + // ================================================================= + + public function test15_QueryTemplates(): void + { + echo "\n๐Ÿ“„ Testing template query...\n"; + + // snippet-start: V2QueryTemplates + $response = $this->moderationClient->v2QueryTemplates(); + // snippet-stop: V2QueryTemplates + + $this->assertResponseSuccess($response, 'query templates'); + + echo "โœ… Successfully queried moderation templates\n"; + } + + // ================================================================= + // HELPER METHODS + // ================================================================= + + private function assertResponseSuccess(StreamResponse $response, string $operation): void + { + if (!$response->isSuccessful()) { + $this->fail("Failed to {$operation}: " . $response->getRawBody()); + } + $this->assertTrue($response->isSuccessful(), "Response should be successful for {$operation}"); + } + + private function cleanupResources(): void + { + echo "\n๐Ÿงน Cleaning up moderation test resources...\n"; + + // Unban any remaining banned users + if (!empty($this->bannedUserIds)) { + foreach ($this->bannedUserIds as $userId) { + try { + $request = new GeneratedModels\UnbanRequest( + unbannedByID: $this->moderatorUserId + ); + $this->moderationClient->unban($userId, '', '', $request); + echo "โœ… Cleaned up ban for user: {$userId}\n"; + } catch (StreamApiException $e) { + echo "Warning: Failed to unban user {$userId}: " . $e->getMessage() . "\n"; + } + } + } + + // Unmute any remaining muted users + if (!empty($this->mutedUserIds)) { + foreach ($this->mutedUserIds as $userId) { + try { + $request = new GeneratedModels\UnmuteRequest( + targetIds: [$userId], + userID: $this->moderatorUserId + ); + $this->moderationClient->unmute($request); + echo "โœ… Cleaned up mute for user: {$userId}\n"; + } catch (StreamApiException $e) { + echo "Warning: Failed to unmute user {$userId}: " . $e->getMessage() . "\n"; + } + } + } + + // Delete any created moderation configs + if (!empty($this->createdConfigs)) { + foreach ($this->createdConfigs as $configKey) { + try { + $this->moderationClient->deleteConfig($configKey, 'default'); + echo "โœ… Cleaned up config: {$configKey}\n"; + } catch (StreamApiException $e) { + echo "Warning: Failed to delete config {$configKey}: " . $e->getMessage() . "\n"; + } + } + } + + echo "๐Ÿงน Moderation cleanup completed\n"; + } +}