From d7f56bced1b7b75cec49dede319610a1ce15cdf3 Mon Sep 17 00:00:00 2001 From: Touhidur Rahman Date: Sun, 1 Mar 2026 01:14:23 +0600 Subject: [PATCH 1/2] pkp/plagiarism#100 safety first approach for webhook registration to avoid 409 conflict --- IThenticate.php | 74 ++++++++++++++++++- PlagiarismPlugin.php | 46 +++++++++--- PlagiarismSettingsForm.php | 8 +- TestIthenticate.php | 18 +++++ .../PlagiarismIthenticateActionHandler.php | 4 +- 5 files changed, 134 insertions(+), 16 deletions(-) diff --git a/IThenticate.php b/IThenticate.php index 2d9abdd5..81b00a24 100644 --- a/IThenticate.php +++ b/IThenticate.php @@ -587,11 +587,46 @@ public function registerWebhook( 'exceptions' => false, ]); - if ($response && $response->getStatusCode() === 201) { + if (!$response) { + return null; + } + + $responseStatusCode = $response->getStatusCode(); + + if ($responseStatusCode === 201) { $result = json_decode($response->getBody()->getContents()); return $result->id; } + // Handle 409 CONFLICT — a webhook with the same URL already exists. + // This happens when a previous registration succeeded at iThenticate but the + // webhook ID was not saved locally (e.g. DB save failed after API success). + // Recovery: find the orphaned webhook, delete it, and retry registration once. + if ($responseStatusCode === 409) { + $existingWebhookId = $this->findWebhookIdByUrl($url); + + if ($existingWebhookId && $this->deleteWebhook($existingWebhookId)) { + $retryResponse = $this->makeApiRequest('POST', $this->getApiPath('webhooks'), [ + 'headers' => array_merge($this->getRequiredHeaders(), [ + 'Content-Type' => 'application/json', + ]), + 'json' => [ + 'signing_secret' => base64_encode($signingSecret), + 'url' => $url, + 'event_types' => $events, + 'allow_insecure' => true, + ], + 'verify' => false, + 'exceptions' => false, + ]); + + if ($retryResponse && $retryResponse->getStatusCode() === 201) { + $result = json_decode($retryResponse->getBody()->getContents()); + return $result->id; + } + } + } + return null; } @@ -630,6 +665,43 @@ public function validateWebhook(string $webhookId, ?string &$result = null): boo return false; } + /** + * List all registered webhooks + * @see https://developers.turnitin.com/docs/tca#list-webhooks + * + * @return array List of webhook associative arrays, or empty array on failure + */ + public function listWebhooks(): array + { + $response = $this->makeApiRequest('GET', $this->getApiPath('webhooks'), [ + 'headers' => $this->getRequiredHeaders(), + 'verify' => false, + 'exceptions' => false, + ]); + + if ($response && $response->getStatusCode() === 200) { + return json_decode($response->getBody()->getContents(), true) ?? []; + } + + return []; + } + + /** + * Find a webhook ID by its URL from the list of registered webhooks + * + * @return string|null The webhook ID if found, or null + */ + public function findWebhookIdByUrl(string $url): ?string + { + foreach ($this->listWebhooks() as $webhook) { + if (($webhook['url'] ?? null) === $url) { + return $webhook['id'] ?? null; + } + } + + return null; + } + /** * Get the stored EULA details */ diff --git a/PlagiarismPlugin.php b/PlagiarismPlugin.php index 45504e50..dff8989a 100644 --- a/PlagiarismPlugin.php +++ b/PlagiarismPlugin.php @@ -842,32 +842,54 @@ public function createNewSubmission( } /** - * Register the webhook for this context + * Get the webhook URL for a given context + * + * Format: BASE_URL/index.php/CONTEXT_PATH/$$$call$$$/plugins/generic/plagiarism/controllers/plagiarism-webhook/handle */ - public function registerIthenticateWebhook(IThenticate|TestIThenticate $ithenticate, ?Context $context = null): bool + public function getWebhookUrl(?Context $context = null): string { $request = Application::get()->getRequest(); $context ??= $request->getContext(); - $signingSecret = \Illuminate\Support\Str::random(12); - - // Example webhook url : BASE_URL/index.php/CONTEXT_PATH/$$$call$$$/plugins/generic/plagiarism/controllers/plagiarism-webhook/handle - $webhookUrl = Application::get()->getDispatcher()->url( + return Application::get()->getDispatcher()->url( $request, Application::ROUTE_COMPONENT, $context->getData('urlPath'), 'plugins.generic.plagiarism.controllers.PlagiarismWebhookHandler', 'handle' ); + } + + /** + * Register the webhook for this context + * + * + * Example webhook format : BASE_URL/index.php/CONTEXT_PATH/$$$call$$$/plugins/generic/plagiarism/controllers/plagiarism-webhook/handle + */ + public function registerIthenticateWebhook(IThenticate|TestIThenticate $ithenticate, ?Context $context = null): bool + { + $request = Application::get()->getRequest(); + $context ??= $request->getContext(); + + $signingSecret = \Illuminate\Support\Str::random(12); + $webhookUrl = $this->getWebhookUrl($context); if ($webhookId = $ithenticate->registerWebhook($signingSecret, $webhookUrl)) { - $contextService = Services::get('context'); /** @var \PKP\Services\PKPContextService $contextService */ - $context = $contextService->edit($context, [ - 'ithenticateWebhookSigningSecret' => $signingSecret, - 'ithenticateWebhookId' => $webhookId - ], $request); + try { + $contextService = Services::get('context'); /** @var \PKP\Services\PKPContextService $contextService */ + $context = $contextService->edit($context, [ + 'ithenticateWebhookSigningSecret' => $signingSecret, + 'ithenticateWebhookId' => $webhookId + ], $request); + + return true; + } catch (Throwable $e) { + // DB save failed after API registration succeeded — clean up orphaned webhook + error_log("Webhook registered at iThenticate (ID: {$webhookId}) but failed to save to DB for context {$context->getId()}: " . $e->getMessage()); + $ithenticate->deleteWebhook($webhookId); - return true; + return false; + } } error_log("unable to complete the iThenticate webhook registration for context id {$context->getId()}"); diff --git a/PlagiarismSettingsForm.php b/PlagiarismSettingsForm.php index 6bd18b73..3052f483 100644 --- a/PlagiarismSettingsForm.php +++ b/PlagiarismSettingsForm.php @@ -152,10 +152,14 @@ public function execute(...$functionArgs) // If there is a already registered webhook for this context, need to delete it first // before creating a new one as webhook URL remains same which will return 409(HTTP_CONFLICT) if ($this->_context->getData('ithenticateWebhookId')) { - $ithenticate->deleteWebhook($this->_context->getData('ithenticateWebhookId')); + if (!$ithenticate->deleteWebhook($this->_context->getData('ithenticateWebhookId'))) { + error_log("Failed to delete existing iThenticate webhook {$this->_context->getData('ithenticateWebhookId')} for context {$this->_context->getId()}"); + } } - $this->_plugin->registerIthenticateWebhook($ithenticate); + if (!$this->_plugin->registerIthenticateWebhook($ithenticate, $this->_context)) { + error_log("Failed to register iThenticate webhook for context {$this->_context->getId()}"); + } } $this->_plugin->updateSetting($this->_context->getId(), 'ithenticateApiUrl', $ithenticateApiUrl, 'string'); diff --git a/TestIthenticate.php b/TestIthenticate.php index 4896b226..add39a54 100644 --- a/TestIthenticate.php +++ b/TestIthenticate.php @@ -423,6 +423,24 @@ public function validateWebhook(string $webhookId, ?string &$result = null): boo return true; } + /** + * @copydoc IThenticate::listWebhooks() + */ + public function listWebhooks(): array + { + error_log("Listing all registered webhooks"); + return []; + } + + /** + * @copydoc IThenticate::findWebhookIdByUrl() + */ + public function findWebhookIdByUrl(string $url): ?string + { + error_log("Finding webhook by URL: {$url}"); + return null; + } + /** * @copydoc IThenticate::getEulaDetails() */ diff --git a/controllers/PlagiarismIthenticateActionHandler.php b/controllers/PlagiarismIthenticateActionHandler.php index 2d4f1446..7724f56e 100644 --- a/controllers/PlagiarismIthenticateActionHandler.php +++ b/controllers/PlagiarismIthenticateActionHandler.php @@ -297,7 +297,9 @@ public function submitSubmission(array $args, Request $request) // If no webhook previously registered for this Context, register it if (!$context->getData('ithenticateWebhookId')) { - $this->_plugin->registerIthenticateWebhook($ithenticate, $context); + if (!$this->_plugin->registerIthenticateWebhook($ithenticate, $context)) { + error_log("Webhook registration failed for context {$context->getId()} during manual submission"); + } } // As the submission has been already and should be stamped with an EULA at the From 0f26d101439e2ab747bc99c3348987106208eaa4 Mon Sep 17 00:00:00 2001 From: Touhidur Rahman Date: Sun, 1 Mar 2026 15:16:16 +0600 Subject: [PATCH 2/2] pkp/plagiarism#100 webhook cli enhancement --- IThenticate.php | 59 ++++- README.md | 19 +- TestIthenticate.php | 21 ++ WEBHOOK_CLI_USAGE.md | 368 ++++++++++++++++++++++++++++++ locale/ar/locale.po | 44 ++++ locale/bg/locale.po | 44 ++++ locale/ca/locale.po | 44 ++++ locale/cs/locale.po | 44 ++++ locale/da/locale.po | 44 ++++ locale/de/locale.po | 44 ++++ locale/el/locale.po | 44 ++++ locale/en/locale.po | 33 +++ locale/es/locale.po | 44 ++++ locale/fi/locale.po | 44 ++++ locale/fr_CA/locale.po | 44 ++++ locale/gl/locale.po | 44 ++++ locale/hy/locale.po | 44 ++++ locale/id/locale.po | 44 ++++ locale/it/locale.po | 44 ++++ locale/ja/locale.po | 44 ++++ locale/ka/locale.po | 44 ++++ locale/ky/locale.po | 44 ++++ locale/mk/locale.po | 44 ++++ locale/ms/locale.po | 44 ++++ locale/nb/locale.po | 44 ++++ locale/pt/locale.po | 44 ++++ locale/pt_BR/locale.po | 44 ++++ locale/ru/locale.po | 44 ++++ locale/sl/locale.po | 44 ++++ locale/sv/locale.po | 44 ++++ locale/tr/locale.po | 44 ++++ locale/uk/locale.po | 44 ++++ locale/vi/locale.po | 44 ++++ tools/webhook.php | 504 ++++++++++++++++++++++++++++++++++------- 34 files changed, 2139 insertions(+), 97 deletions(-) create mode 100644 WEBHOOK_CLI_USAGE.md diff --git a/IThenticate.php b/IThenticate.php index 81b00a24..0756766f 100644 --- a/IThenticate.php +++ b/IThenticate.php @@ -73,6 +73,12 @@ class IThenticate */ protected ?string $cachedEnabledFeatures = null; + /** + * Store the last API response details for debugging/inspection + * Contains: status_code, body, headers, reason + */ + protected ?array $lastResponseDetails = null; + /** * The default EULA version placeholder to retrieve the current latest version * @@ -753,11 +759,37 @@ public function makeApiRequest( try { $response = Application::get()->getHttpClient()->request($method, $url, $options); + + // Store response details on success + $body = $response->getBody(); + $bodyContent = $body->getContents(); + + $this->lastResponseDetails = [ + 'status_code' => $response->getStatusCode(), + 'body' => $bodyContent, + 'headers' => $response->getHeaders(), + 'reason' => $response->getReasonPhrase(), + ]; + + // Rewind so existing code can still read the body + if ($body->isSeekable()) { + $body->rewind(); + } + } catch (\Throwable $exception) { - + $exceptionMessage = null; - if ($exception instanceof \GuzzleHttp\Exception\RequestException) { - $exceptionMessage = $exception->getResponse()->getBody()->getContents(); + if ($exception instanceof \GuzzleHttp\Exception\RequestException && $exception->hasResponse()) { + $errorResponse = $exception->getResponse(); + $exceptionMessage = $errorResponse->getBody()->getContents(); + + // Store response details on failure + $this->lastResponseDetails = [ + 'status_code' => $errorResponse->getStatusCode(), + 'body' => $exceptionMessage, + 'headers' => $errorResponse->getHeaders(), + 'reason' => $errorResponse->getReasonPhrase(), + ]; } // Mask the sensitive Authorization Bearer token to hide API KEY before logging @@ -826,6 +858,27 @@ public function getApplicableLocale(string|array $locales, ?string $eulaVersion return static::DEFAULT_EULA_LANGUAGE; } + /** + * Get the last API response details including status code, body, headers, and reason phrase + * + * @return array|null Array with keys: status_code, body, headers, reason. + * Returns null if no API call has been made yet. + */ + public function getLastResponseDetails(): ?array + { + return $this->lastResponseDetails; + } + + /** + * Get only the last response body content + * + * @return string|null The response body content, or null if no API call has been made yet. + */ + public function getLastResponseBody(): ?string + { + return $this->lastResponseDetails['body'] ?? null; + } + /** * Get the corresponding available locale or return null */ diff --git a/README.md b/README.md index fcb789d0..2a092576 100644 --- a/README.md +++ b/README.md @@ -90,30 +90,21 @@ When you update(after initial configuration) iThenticate API credentials in `con The webhook command-line tool helps you manage iThenticate webhooks for your contexts. -**Basic Usage:** - ```bash # Register webhooks for a specific journal/press/server -php plugins/generic/plagiarism/tools/webhook.php register --context=yourcontextpath +php plugins/generic/plagiarism/tools/webhook.php register --context=yourjournalpath -# Update existing webhooks (useful after changing API credentials), use --force to force update -php plugins/generic/plagiarism/tools/webhook.php update --context=yourcontextpath +# Update existing webhooks (useful after changing API credentials) +php plugins/generic/plagiarism/tools/webhook.php update --context=yourjournalpath # Validate webhook configuration -php plugins/generic/plagiarism/tools/webhook.php validate --context=yourcontextpath +php plugins/generic/plagiarism/tools/webhook.php validate --context=yourjournalpath # List all configured webhooks php plugins/generic/plagiarism/tools/webhook.php list ``` -**When to use:** -- After changing `api_url` or `api_key` in `config.inc.php` -- To verify webhook configuration is working correctly -- To troubleshoot similarity score delivery issues - -**Finding your context path:** -- From `Administration --> Hosted Journals --> Settings Wizard ` -- Or use the context ID number instead of the path +For detailed usage including all commands, flags, and advanced features (API-level operations, orphaned webhook recovery, duplicate cleanup, and more), see the [Webhook CLI Usage Guide](WEBHOOK_CLI_USAGE.md). ## Restrictions 1. The submitting user must confirm the iThenticate End User License Agreement to send files to iThenticate service for plagiarism checking. diff --git a/TestIthenticate.php b/TestIthenticate.php index add39a54..4e668f16 100644 --- a/TestIthenticate.php +++ b/TestIthenticate.php @@ -77,6 +77,11 @@ class TestIThenticate */ protected ?string $cachedEnabledFeatures = null; + /** + * @copydoc IThenticate::$lastResponseDetails + */ + protected ?array $lastResponseDetails = null; + /** * @copydoc IThenticate::DEFAULT_EULA_VERSION */ @@ -510,6 +515,22 @@ public function getApplicableLocale(string|array $locales, ?string $eulaVersion return static::DEFAULT_EULA_LANGUAGE; } + /** + * @copydoc IThenticate::getLastResponseDetails() + */ + public function getLastResponseDetails(): ?array + { + return $this->lastResponseDetails; + } + + /** + * @copydoc IThenticate::getLastResponseBody() + */ + public function getLastResponseBody(): ?string + { + return $this->lastResponseDetails['body'] ?? null; + } + /** * @copydoc IThenticate::isCorrespondingLocaleAvailable() */ diff --git a/WEBHOOK_CLI_USAGE.md b/WEBHOOK_CLI_USAGE.md new file mode 100644 index 00000000..b9ce559d --- /dev/null +++ b/WEBHOOK_CLI_USAGE.md @@ -0,0 +1,368 @@ +# Webhook CLI Usage Guide + +Command-line tool for managing iThenticate webhook registrations. + +```bash +php plugins/generic/plagiarism/tools/webhook.php [OPTIONS] +``` + +## Quick Start + +```bash +# 1. Register a webhook for your journal +php plugins/generic/plagiarism/tools/webhook.php register --context=yourjournalpath + +# 2. Validate it's working +php plugins/generic/plagiarism/tools/webhook.php validate --context=yourjournalpath + +# 3. List all configured webhooks +php plugins/generic/plagiarism/tools/webhook.php list +``` + +--- + +## Commands + +### register + +Register a new webhook for a context. Idempotent — checks if a webhook already exists before creating one. + +```bash +php plugins/generic/plagiarism/tools/webhook.php register --context=journal-slug +php plugins/generic/plagiarism/tools/webhook.php register --context=1 +``` + +**Behavior:** +- Checks if a webhook already exists (in DB, or in both DB and API with `--include-api`) +- If a valid webhook exists, displays a warning and exits +- If missing, creates a new webhook via `update` + +**With `--include-api`:** +```bash +php plugins/generic/plagiarism/tools/webhook.php register --include-api --context=journal-slug +``` +- Checks both DB and iThenticate API for an existing webhook +- Reports **orphaned** state if found at API but not in DB +- Reports **mismatch** if DB and API have different webhook IDs for the same URL + +**Success output:** +``` +Operation completed successfully. +┌──────────────┬─────────────────────────┬─────────────────┬───────────────┐ +│ id │ url │ event_types │ url reachable │ +├──────────────┼─────────────────────────┼─────────────────┼───────────────┤ +│ webhook-456 │ https://example.com/... │ SUBMISSION_... │ YES │ +└──────────────┴─────────────────────────┴─────────────────┴───────────────┘ +``` + +--- + +### update + +Delete existing webhook (if any) and register a new one with a fresh signing secret. + +```bash +# Normal update +php plugins/generic/plagiarism/tools/webhook.php update --context=journal-slug + +# Force update (continue even if API deletion fails) +php plugins/generic/plagiarism/tools/webhook.php update --context=journal-slug --force + +# Full orphaned webhook recovery (find by URL at API, delete, re-register) +php plugins/generic/plagiarism/tools/webhook.php update --include-api --context=journal-slug +``` + +**When to use:** +- After changing API credentials (`api_url` or `api_key`) +- Webhook URL changed (server migration) +- Signing secret needs rotation +- Recovering from orphaned webhook state + +--- + +### delete + +Delete a webhook from iThenticate API and clear local database records. + +```bash +# Delete using webhook ID from database +php plugins/generic/plagiarism/tools/webhook.php delete --context=journal-slug + +# Delete with API-level lookup (finds webhook by URL) +php plugins/generic/plagiarism/tools/webhook.php delete --include-api --context=journal-slug + +# Delete a specific webhook by ID (no context needed) +php plugins/generic/plagiarism/tools/webhook.php delete --include-api \ + --api-url=https://app.ithenticate.com/api --api-key=KEY --webhook-id=abc-123 + +# Force delete (skip API deletion failure) +php plugins/generic/plagiarism/tools/webhook.php delete --context=journal-slug --force +``` + +**Behavior:** +- Resolves webhook ID using the [priority order](#webhook-id-resolution) +- Deletes from iThenticate API +- Clears DB records only if the deleted webhook ID matches what's stored in the database +- If the webhook is not found at the API (404), warns but proceeds to clean up the DB record +- If `--webhook-id` differs from the DB record, preserves the DB record (useful for cleaning up duplicates) + +**Output examples:** +``` +# Success +Successfully deleted the iThenticate webhook with id: webhook-uuid-123 for context id: 1 + +# Nothing to delete (DB only) +No webhook found in the database for this context. Use --include-api to also check the iThenticate API. + +# Nothing to delete (with --include-api) +No webhook found at iThenticate API for this context. Nothing to delete. + +# Webhook already gone from API +Webhook abc-123 was not found at iThenticate API (may have been deleted already). +Cleaning up local database record. + +# DB record preserved (deleted ID differs from DB) +Deleted webhook explicit-id differs from the database record (db-stored-id). +Database record preserved. +``` + +--- + +### validate + +Verify webhook configuration and test URL reachability. + +```bash +# Validate using webhook ID from database +php plugins/generic/plagiarism/tools/webhook.php validate --context=journal-slug + +# Validate with API lookup (find webhook by URL) +php plugins/generic/plagiarism/tools/webhook.php validate --include-api --context=journal-slug + +# Validate a specific webhook (no context needed) +php plugins/generic/plagiarism/tools/webhook.php validate --include-api \ + --api-url=URL --api-key=KEY --webhook-id=ID +``` + +**Behavior:** +- Retrieves webhook configuration from iThenticate API +- Tests URL accessibility (HEAD then GET request, 10-second timeout) +- Displays configuration table with reachability status +- With `--include-api`: warns if the validated webhook ID differs from the DB record + +**Success output:** +``` +┌────────────────────┬──────────────────────────────────────┬─────────────────┬───────────────┐ +│ id │ url │ event_types │ url reachable │ +├────────────────────┼──────────────────────────────────────┼─────────────────┼───────────────┤ +│ abc123-webhook-id │ https://journal.com/webhooks/handle │ SUBMISSION_C... │ YES │ +└────────────────────┴──────────────────────────────────────┴─────────────────┴───────────────┘ +``` + +**On failure**, full API response details are displayed for debugging (status code, response body, headers). + +--- + +### list + +List webhook configurations for all contexts and optionally from iThenticate API. + +```bash +# List all contexts and their DB webhook status +php plugins/generic/plagiarism/tools/webhook.php list + +# Include API webhooks with context cross-reference +php plugins/generic/plagiarism/tools/webhook.php list --include-api --context=journal-slug + +# API-only listing with explicit credentials +php plugins/generic/plagiarism/tools/webhook.php list --include-api \ + --api-url=https://app.ithenticate.com/api --api-key=YOUR_KEY +``` + +**DB output (default):** +``` +┌────┬─────────────┬──────────────────┬────────────┐ +│ ID │ Path │ Webhook ID │ Configured │ +├────┼─────────────┼──────────────────┼────────────┤ +│ 1 │ testjournal │ webhook-uuid-123 │ Yes │ +│ 2 │ journal2 │ Not configured │ No │ +└────┴─────────────┴──────────────────┴────────────┘ +``` + +**API output (`--include-api`):** + +Each API webhook is displayed as a card with wrapped values: +``` +API Webhooks (iThenticate) +-------------------------- + +Webhook 1 of 2 +┌─────────────────┬────────────────────────────────────────────────────────────┐ +│ Property │ Value │ +├─────────────────┼────────────────────────────────────────────────────────────┤ +│ Webhook ID │ webhook-uuid-123 │ +│ URL │ https://site.com/index.php/journal/$$$call$$$/plugins/gen │ +│ │ eric/plagiarism/controllers/plagiarism-webhook/handle │ +│ Events │ SUBMISSION_COMPLETE, SIMILARITY_UPDATED, PDF_STATUS, │ +│ │ GROUP_ATTACHMENT_COMPLETE, SIMILARITY_COMPLETE │ +│ Created │ 2025-11-26T10:30:00.000Z │ +│ Matches Context │ YES (URL + DB) │ +└─────────────────┴────────────────────────────────────────────────────────────┘ +``` + +**"Matches Context" values:** +| Value | Meaning | +|-------|---------| +| `YES (URL + DB)` | Healthy — matches both context URL and DB record | +| `YES (URL match, not in DB)` | Orphaned — URL matches but not tracked in DB | +| `YES (DB match, URL differs)` | Stale — DB has this ID but URL has changed | +| `-` | No match to the current context | + +--- + +### usage + +Display help information about available commands. + +```bash +php plugins/generic/plagiarism/tools/webhook.php usage +``` + +--- + +## Global Options + +| Option | Description | +|--------|-------------| +| `--context=` | Context path or numeric ID | +| `--include-api` | Include iThenticate API-level operations alongside DB | +| `--api-url=` | Explicit iThenticate API URL (overrides context credentials) | +| `--api-key=` | Explicit iThenticate API key (overrides context credentials) | +| `--webhook-id=` | Explicit webhook ID (bypasses URL-based lookup) | +| `--force` | Skip failures and force operations | + +### When is `--context` required? + +| Command | Without `--include-api` | With `--include-api` | +|---------|------------------------|---------------------| +| register | Required | Required | +| update | Required | Required | +| delete | Required | Required, unless `--webhook-id` + `--api-url` + `--api-key` | +| validate | Required | Required, unless `--webhook-id` + `--api-url` + `--api-key` | +| list | Not required | Required, unless `--api-url` + `--api-key` | + +### Credential Resolution Order + +When API access is needed, credentials are resolved in priority order: + +1. **Explicit CLI params** (`--api-key` + `--api-url`) — highest priority +2. **Context forced credentials** (from `[ithenticate]` section in `config.inc.php`) +3. **Context plugin settings** (from database) + +--- + +## Webhook ID Resolution + +When a command needs to determine which webhook to operate on, the ID is resolved in this order: + +1. **Explicit `--webhook-id`** — always used if provided (highest priority) +2. **API lookup by URL** — if `--include-api` is set and context is available, finds the webhook at iThenticate API that matches the context's URL +3. **DB-stored ID** — falls back to the `ithenticateWebhookId` stored in the database for the context + +--- + +## Common Scenarios + +### Initial Setup + +```bash +# Register webhook for each journal/press/server +php plugins/generic/plagiarism/tools/webhook.php register --context=journal1 +php plugins/generic/plagiarism/tools/webhook.php register --context=journal2 + +# Verify they're working +php plugins/generic/plagiarism/tools/webhook.php validate --context=journal1 +php plugins/generic/plagiarism/tools/webhook.php validate --context=journal2 +``` + +### After Changing API Credentials + +```bash +# Update webhooks (deletes old, registers new) +php plugins/generic/plagiarism/tools/webhook.php update --context=journal-slug + +# Validate the new webhook +php plugins/generic/plagiarism/tools/webhook.php validate --context=journal-slug +``` + +### Orphaned Webhook Recovery + +A webhook is "orphaned" when it exists at iThenticate API but isn't tracked in your database (e.g., the DB save failed after API registration). + +**Symptoms:** +- `list` shows "Not configured" for the context +- `register` fails (webhook URL already exists at API) + +**One-command fix:** +```bash +php plugins/generic/plagiarism/tools/webhook.php update --include-api --context=journal-slug +``` + +**Step-by-step diagnosis:** +```bash +# 1. See what's at the API +php plugins/generic/plagiarism/tools/webhook.php list --include-api --context=journal-slug +# Look for "YES (URL match, not in DB)" in the Matches Context column + +# 2. Delete the orphaned webhook +php plugins/generic/plagiarism/tools/webhook.php delete --include-api --context=journal-slug + +# 3. Re-register properly +php plugins/generic/plagiarism/tools/webhook.php register --context=journal-slug +``` + +### Cleaning Up Duplicate Webhooks + +If multiple webhooks were accidentally registered for the same URL: + +```bash +# 1. List all API webhooks to see duplicates +php plugins/generic/plagiarism/tools/webhook.php list --include-api --context=journal-slug + +# 2. Delete specific unwanted webhooks by ID +php plugins/generic/plagiarism/tools/webhook.php delete --include-api \ + --api-url=URL --api-key=KEY --webhook-id=UNWANTED_ID + +# 3. Repeat for each duplicate +``` + +### Server Migration / URL Change + +```bash +# Update webhook with new URL (deletes old, registers with new URL) +php plugins/generic/plagiarism/tools/webhook.php update --context=journal-slug + +# If old webhook is orphaned at API (URL changed, can't find by new URL) +php plugins/generic/plagiarism/tools/webhook.php update --context=journal-slug --force +``` + +### API Audit (No Context Needed) + +```bash +# List all webhooks registered for your iThenticate account +php plugins/generic/plagiarism/tools/webhook.php list --include-api \ + --api-url=https://app.ithenticate.com/api --api-key=YOUR_KEY +``` + +## Finding Your Context Path + +The `--context` option accepts either a **path** or a **numeric ID**: + +- **Path**: Found in `Administration > Hosted Journals > Settings Wizard` (the URL path for your journal) +- **ID**: The numeric context ID from the database + +Both are interchangeable: +```bash +php plugins/generic/plagiarism/tools/webhook.php register --context=myjournal +php plugins/generic/plagiarism/tools/webhook.php register --context=1 +``` diff --git a/locale/ar/locale.po b/locale/ar/locale.po index 44c688ab..1f9f9104 100644 --- a/locale/ar/locale.po +++ b/locale/ar/locale.po @@ -277,3 +277,47 @@ msgstr "تم حذف الخطاف الإلكتروني لـ iThenticate بنجا #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "تعذر حذف الخطاف الإلكتروني لـ iThenticate بالمعرف: {$webhookId} لمعرف السياق: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "حذف الخطاف الإلكتروني لحساب iThenticate لمسار سياق محدد" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "بيانات اعتماد واجهة برمجة التطبيق مطلوبة. قدّم --api-url و --api-key، أو --context لاستخدام بيانات الاعتماد المخزنة." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "لم يتم العثور على خطاف إلكتروني في واجهة برمجة التطبيق لـ iThenticate لهذا السياق. لا يوجد شيء للحذف." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "يوجد خطاف إلكتروني في واجهة برمجة التطبيق لـ iThenticate (المعرف: {$webhookId}، الرابط: {$url}) لكنه غير موجود في قاعدة البيانات. استخدم 'update --include-api' للحذف وإعادة التسجيل، أو 'delete --include-api' لإزالته." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "لم يتم العثور على خطافات إلكترونية في واجهة برمجة التطبيق لـ iThenticate لبيانات الاعتماد المقدمة." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "يوجد خطاف إلكتروني بالفعل في واجهة برمجة التطبيق لـ iThenticate بالمعرف: {$webhookId} للرابط: {$url}. استخدم 'update --include-api' لاستبداله." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "لم يتم العثور على خطاف إلكتروني في قاعدة البيانات لهذا السياق. استخدم --include-api للتحقق أيضًا من واجهة برمجة التطبيق لـ iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "لم يتم العثور على الخطاف الإلكتروني {$webhookId} في واجهة برمجة التطبيق لـ iThenticate (ربما تم حذفه بالفعل). جارٍ تنظيف سجل قاعدة البيانات المحلية." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "الخطاف الإلكتروني المحذوف {$deletedId} يختلف عن سجل قاعدة البيانات ({$dbId}). تم الحفاظ على سجل قاعدة البيانات." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "عدم تطابق معرف الخطاف الإلكتروني: قاعدة البيانات تحتوي على {$dbId} لكن واجهة برمجة التطبيق لـ iThenticate تحتوي على {$apiId} للرابط {$url}. استخدم 'update --include-api' للحل." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "ملاحظة: الخطاف الإلكتروني الذي تم التحقق منه {$validatedId} (من واجهة برمجة التطبيق) يختلف عن سجل قاعدة البيانات ({$dbId})." diff --git a/locale/bg/locale.po b/locale/bg/locale.po index 11a1af07..964485d0 100644 --- a/locale/bg/locale.po +++ b/locale/bg/locale.po @@ -406,3 +406,47 @@ msgstr "Успешно изтрит webhook за iThenticate с ID: {$webhookId} #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Не може да се изтрие webhook за iThenticate с ID: {$webhookId} за контекст ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Изтриване на webhook за акаунт в iThenticate за зададен контекстен път" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Необходими са API данни за достъп. Предоставете --api-url и --api-key, или --context за използване на съхранените данни за достъп." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Не е намерен webhook в iThenticate API за този контекст. Няма какво да се изтрие." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook съществува в iThenticate API (id: {$webhookId}, url: {$url}), но НЕ е в базата данни. Използвайте 'update --include-api' за изтриване и повторна регистрация, или 'delete --include-api' за премахване." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Не са намерени webhooks в iThenticate API за предоставените данни за достъп." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Webhook вече съществува в iThenticate API с id: {$webhookId} за URL: {$url}. Използвайте 'update --include-api' за замяна." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Не е намерен webhook в базата данни за този контекст. Използвайте --include-api за проверка и в iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} не е намерен в iThenticate API (може вече да е бил изтрит). Почистване на локалния запис в базата данни." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Изтритият webhook {$deletedId} се различава от записа в базата данни ({$dbId}). Записът в базата данни е запазен." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Несъответствие на webhook ID: базата данни съдържа {$dbId}, но iThenticate API съдържа {$apiId} за URL {$url}. Използвайте 'update --include-api' за разрешаване." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Забележка: Валидираният webhook {$validatedId} (от API) се различава от записа в базата данни ({$dbId})." diff --git a/locale/ca/locale.po b/locale/ca/locale.po index 45aa0215..ff7a1c4c 100644 --- a/locale/ca/locale.po +++ b/locale/ca/locale.po @@ -92,3 +92,47 @@ msgstr "S'ha eliminat correctament el webhook d'iThenticate amb l'ID: {$webhookI #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "No s'ha pogut eliminar el webhook d'iThenticate amb l'ID: {$webhookId} per al context ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Eliminar el webhook per al compte d'iThenticate per a una ruta de context donada" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Credencials de l'API requerides. Proporcioneu --api-url i --api-key, o --context per utilitzar les credencials emmagatzemades." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "No s'ha trobat cap webhook a l'API d'iThenticate per a aquest context. No hi ha res a eliminar." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "El webhook existeix a l'API d'iThenticate (id: {$webhookId}, url: {$url}) però NO es troba a la base de dades. Utilitzeu 'update --include-api' per eliminar i tornar a registrar, o 'delete --include-api' per eliminar-lo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "No s'han trobat webhooks a l'API d'iThenticate per a les credencials proporcionades." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Ja existeix un webhook a l'API d'iThenticate amb l'id: {$webhookId} per a l'URL: {$url}. Utilitzeu 'update --include-api' per reemplaçar-lo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "No s'ha trobat cap webhook a la base de dades per a aquest context. Utilitzeu --include-api per comprovar també l'API d'iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "El webhook {$webhookId} no s'ha trobat a l'API d'iThenticate (potser ja s'ha eliminat). S'està netejant el registre local de la base de dades." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "El webhook eliminat {$deletedId} difereix del registre de la base de dades ({$dbId}). El registre de la base de dades s'ha preservat." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Discrepància d'ID del webhook: la base de dades conté {$dbId} però l'API d'iThenticate conté {$apiId} per a l'URL {$url}. Utilitzeu 'update --include-api' per resoldre-ho." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Nota: El webhook validat {$validatedId} (de l'API) difereix del registre de la base de dades ({$dbId})." diff --git a/locale/cs/locale.po b/locale/cs/locale.po index e074961d..55c819df 100644 --- a/locale/cs/locale.po +++ b/locale/cs/locale.po @@ -386,3 +386,47 @@ msgstr "Úspěšně odstraněn webhook iThenticate s ID: {$webhookId} pro kontex #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Nelze odstranit webhook iThenticate s ID: {$webhookId} pro kontext ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Odstranit webhook pro účet iThenticate pro danou cestu kontextu" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Jsou vyžadovány přihlašovací údaje API. Zadejte --api-url a --api-key, nebo --context pro použití uložených přihlašovacích údajů." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Nebyl nalezen žádný webhook v iThenticate API pro tento kontext. Není co odstranit." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook existuje v iThenticate API (id: {$webhookId}, url: {$url}), ale NENÍ v databázi. Použijte 'update --include-api' pro odstranění a opětovnou registraci, nebo 'delete --include-api' pro odebrání." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Nebyly nalezeny žádné webhooky v iThenticate API pro zadané přihlašovací údaje." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Webhook již existuje v iThenticate API s id: {$webhookId} pro URL: {$url}. Použijte 'update --include-api' pro jeho nahrazení." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Nebyl nalezen žádný webhook v databázi pro tento kontext. Použijte --include-api pro kontrolu také v iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} nebyl nalezen v iThenticate API (mohl být již odstraněn). Probíhá čištění lokálního záznamu v databázi." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Odstraněný webhook {$deletedId} se liší od záznamu v databázi ({$dbId}). Záznam v databázi byl zachován." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Nesoulad ID webhooku: databáze obsahuje {$dbId}, ale iThenticate API obsahuje {$apiId} pro URL {$url}. Použijte 'update --include-api' pro vyřešení." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Poznámka: Ověřený webhook {$validatedId} (z API) se liší od záznamu v databázi ({$dbId})." diff --git a/locale/da/locale.po b/locale/da/locale.po index cc18d28f..dd8cf545 100644 --- a/locale/da/locale.po +++ b/locale/da/locale.po @@ -398,3 +398,47 @@ msgstr "Succesfuldt slettet iThenticate webhook med ID: {$webhookId} for konteks #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Kunne ikke slette iThenticate webhook med ID: {$webhookId} for kontekst ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Slet webhook for iThenticate-konto for en given kontekststi" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "API-legitimationsoplysninger påkrævet. Angiv --api-url og --api-key, eller --context for at bruge gemte legitimationsoplysninger." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Ingen webhook fundet i iThenticate API for denne kontekst. Intet at slette." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook findes i iThenticate API (id: {$webhookId}, url: {$url}), men er IKKE i databasen. Brug 'update --include-api' for at slette og genregistrere, eller 'delete --include-api' for at fjerne den." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Ingen webhooks fundet i iThenticate API for de angivne legitimationsoplysninger." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "En webhook findes allerede i iThenticate API med id: {$webhookId} for URL: {$url}. Brug 'update --include-api' for at erstatte den." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Ingen webhook fundet i databasen for denne kontekst. Brug --include-api for også at tjekke iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} blev ikke fundet i iThenticate API (kan allerede være slettet). Rydder op i lokal databasepost." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Slettet webhook {$deletedId} adskiller sig fra databaseposten ({$dbId}). Databaseposten er bevaret." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Webhook ID-uoverensstemmelse: databasen har {$dbId}, men iThenticate API har {$apiId} for URL {$url}. Brug 'update --include-api' for at løse problemet." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Bemærk: Valideret webhook {$validatedId} (fra API) adskiller sig fra databaseposten ({$dbId})." diff --git a/locale/de/locale.po b/locale/de/locale.po index 7c073c24..af7b0bfc 100644 --- a/locale/de/locale.po +++ b/locale/de/locale.po @@ -403,3 +403,47 @@ msgstr "iThenticate-Webhook mit ID: {$webhookId} erfolgreich gelöscht für Kont #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "iThenticate-Webhook mit ID: {$webhookId} konnte nicht gelöscht werden für Kontext-ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Webhook für iThenticate-Konto für einen bestimmten Kontextpfad löschen" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "API-Zugangsdaten erforderlich. Geben Sie --api-url und --api-key an, oder --context um gespeicherte Zugangsdaten zu verwenden." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Kein Webhook in der iThenticate API für diesen Kontext gefunden. Nichts zu löschen." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook existiert in der iThenticate API (ID: {$webhookId}, URL: {$url}), ist aber NICHT in der Datenbank. Verwenden Sie 'update --include-api' zum Löschen und erneuten Registrieren, oder 'delete --include-api' zum Entfernen." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Keine Webhooks in der iThenticate API für die angegebenen Zugangsdaten gefunden." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Ein Webhook existiert bereits in der iThenticate API mit ID: {$webhookId} für URL: {$url}. Verwenden Sie 'update --include-api' um ihn zu ersetzen." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Kein Webhook in der Datenbank für diesen Kontext gefunden. Verwenden Sie --include-api um auch die iThenticate API zu prüfen." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} wurde nicht in der iThenticate API gefunden (möglicherweise bereits gelöscht). Lokaler Datenbankeintrag wird bereinigt." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Gelöschter Webhook {$deletedId} unterscheidet sich vom Datenbankeintrag ({$dbId}). Datenbankeintrag wurde beibehalten." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Webhook-ID-Abweichung: Datenbank enthält {$dbId}, aber iThenticate API enthält {$apiId} für URL {$url}. Verwenden Sie 'update --include-api' zur Behebung." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Hinweis: Validierter Webhook {$validatedId} (aus API) unterscheidet sich vom Datenbankeintrag ({$dbId})." diff --git a/locale/el/locale.po b/locale/el/locale.po index 64fb2810..dbb23bf7 100644 --- a/locale/el/locale.po +++ b/locale/el/locale.po @@ -94,3 +94,47 @@ msgstr "Επιτυχής διαγραφή του webhook iThenticate με ID: {$ #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Αδυναμία διαγραφής του webhook iThenticate με ID: {$webhookId} για πλαίσιο ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Διαγραφή του webhook για λογαριασμό iThenticate για μια δεδομένη διαδρομή πλαισίου" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Απαιτούνται διαπιστευτήρια API. Παρέχετε --api-url και --api-key, ή --context για χρήση αποθηκευμένων διαπιστευτηρίων." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Δεν βρέθηκε webhook στο iThenticate API για αυτό το πλαίσιο. Τίποτα προς διαγραφή." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Υπάρχει webhook στο iThenticate API (id: {$webhookId}, url: {$url}) αλλά ΔΕΝ βρίσκεται στη βάση δεδομένων. Χρησιμοποιήστε 'update --include-api' για διαγραφή και επανεγγραφή, ή 'delete --include-api' για αφαίρεσή του." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Δεν βρέθηκαν webhooks στο iThenticate API για τα παρεχόμενα διαπιστευτήρια." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Ένα webhook υπάρχει ήδη στο iThenticate API με id: {$webhookId} για URL: {$url}. Χρησιμοποιήστε 'update --include-api' για αντικατάστασή του." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Δεν βρέθηκε webhook στη βάση δεδομένων για αυτό το πλαίσιο. Χρησιμοποιήστε --include-api για έλεγχο και στο iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Το webhook {$webhookId} δεν βρέθηκε στο iThenticate API (μπορεί να έχει ήδη διαγραφεί). Εκκαθάριση τοπικής εγγραφής βάσης δεδομένων." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Το διαγραμμένο webhook {$deletedId} διαφέρει από την εγγραφή βάσης δεδομένων ({$dbId}). Η εγγραφή βάσης δεδομένων διατηρήθηκε." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Ασυμφωνία ID webhook: η βάση δεδομένων έχει {$dbId} αλλά το iThenticate API έχει {$apiId} για URL {$url}. Χρησιμοποιήστε 'update --include-api' για επίλυση." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Σημείωση: Το επικυρωμένο webhook {$validatedId} (από το API) διαφέρει από την εγγραφή βάσης δεδομένων ({$dbId})." diff --git a/locale/en/locale.po b/locale/en/locale.po index d2fd9c41..5d1815fc 100644 --- a/locale/en/locale.po +++ b/locale/en/locale.po @@ -305,3 +305,36 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Delete the webhook for iThenticate account for a given context path" + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "API credentials required. Provide --api-url and --api-key, or --context to use stored credentials." + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "No webhook found at iThenticate API for this context. Nothing to delete." + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook exists at iThenticate API (id: {$webhookId}, url: {$url}) but is NOT in the database. Use 'update --include-api' to delete and re-register, or 'delete --include-api' to remove it." + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "No webhooks found at iThenticate API for the provided credentials." + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "A webhook already exists at iThenticate API with id: {$webhookId} for URL: {$url}. Use 'update --include-api' to replace it." + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "No webhook found in the database for this context. Use --include-api to also check the iThenticate API." + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} was not found at iThenticate API (may have been deleted already). Cleaning up local database record." + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Deleted webhook {$deletedId} differs from the database record ({$dbId}). Database record preserved." + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Webhook ID mismatch: database has {$dbId} but iThenticate API has {$apiId} for URL {$url}. Use 'update --include-api' to resolve." + +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Note: Validated webhook {$validatedId} (from API) differs from database record ({$dbId})." diff --git a/locale/es/locale.po b/locale/es/locale.po index 09b69cfe..40da535b 100644 --- a/locale/es/locale.po +++ b/locale/es/locale.po @@ -397,3 +397,47 @@ msgstr "Webhook iThenticate con ID: {$webhookId} eliminado exitosamente para con #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "No se pudo eliminar el webhook iThenticate con ID: {$webhookId} para contexto ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Eliminar el webhook para la cuenta iThenticate para una ruta de contexto dada" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Se requieren credenciales de API. Proporcione --api-url y --api-key, o --context para usar las credenciales almacenadas." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "No se encontró ningún webhook en la API de iThenticate para este contexto. Nada que eliminar." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Existe un webhook en la API de iThenticate (id: {$webhookId}, url: {$url}) pero NO está en la base de datos. Use 'update --include-api' para eliminar y volver a registrar, o 'delete --include-api' para eliminarlo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "No se encontraron webhooks en la API de iThenticate para las credenciales proporcionadas." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Ya existe un webhook en la API de iThenticate con id: {$webhookId} para URL: {$url}. Use 'update --include-api' para reemplazarlo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "No se encontró ningún webhook en la base de datos para este contexto. Use --include-api para verificar también en la API de iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "El webhook {$webhookId} no se encontró en la API de iThenticate (puede que ya haya sido eliminado). Limpiando el registro local de la base de datos." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "El webhook eliminado {$deletedId} difiere del registro de la base de datos ({$dbId}). El registro de la base de datos se conservó." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Discrepancia de ID de webhook: la base de datos tiene {$dbId} pero la API de iThenticate tiene {$apiId} para URL {$url}. Use 'update --include-api' para resolver." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Nota: El webhook validado {$validatedId} (de la API) difiere del registro de la base de datos ({$dbId})." diff --git a/locale/fi/locale.po b/locale/fi/locale.po index aa6ea816..b855a15a 100644 --- a/locale/fi/locale.po +++ b/locale/fi/locale.po @@ -184,3 +184,47 @@ msgstr "iThenticate-webhook poistettu onnistuneesti ID:llä: {$webhookId} kontek #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "iThenticate-webhookia ei voitu poistaa ID:llä: {$webhookId} kontekstille ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Poista webhook iThenticate-tililtä annetulle kontekstipolulle" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "API-tunnistetiedot vaaditaan. Anna --api-url ja --api-key, tai --context käyttääksesi tallennettuja tunnistetietoja." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Webhookia ei löytynyt iThenticate API:sta tälle kontekstille. Ei poistettavaa." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook löytyy iThenticate API:sta (id: {$webhookId}, url: {$url}) mutta sitä EI ole tietokannassa. Käytä 'update --include-api' poistaaksesi ja rekisteröidäksesi uudelleen, tai 'delete --include-api' poistaaksesi sen." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Webhookeja ei löytynyt iThenticate API:sta annetuilla tunnistetiedoilla." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Webhook on jo olemassa iThenticate API:ssa id:llä: {$webhookId} URL:lle: {$url}. Käytä 'update --include-api' korvataksesi sen." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Webhookia ei löytynyt tietokannasta tälle kontekstille. Käytä --include-api tarkistaaksesi myös iThenticate API:sta." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhookia {$webhookId} ei löytynyt iThenticate API:sta (se on ehkä jo poistettu). Siivotaan paikallinen tietokantatietue." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Poistettu webhook {$deletedId} eroaa tietokantatietueesta ({$dbId}). Tietokantatietue säilytettiin." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Webhook-ID:n ristiriita: tietokannassa on {$dbId} mutta iThenticate API:ssa on {$apiId} URL:lle {$url}. Käytä 'update --include-api' ratkaistaksesi." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Huom: Vahvistettu webhook {$validatedId} (API:sta) eroaa tietokantatietueesta ({$dbId})." diff --git a/locale/fr_CA/locale.po b/locale/fr_CA/locale.po index 56b45280..980f60f5 100644 --- a/locale/fr_CA/locale.po +++ b/locale/fr_CA/locale.po @@ -397,3 +397,47 @@ msgstr "Webhook iThenticate avec l'id : {$webhookId} supprimé avec succès pour #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Impossible de supprimer le webhook iThenticate avec l'id : {$webhookId} pour le contexte id : {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Supprimer le webhook pour le compte iThenticate pour un chemin de contexte donné" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Les identifiants API sont requis. Fournissez --api-url et --api-key, ou --context pour utiliser les identifiants enregistrés." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Aucun webhook trouvé dans l'API iThenticate pour ce contexte. Rien à supprimer." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Un webhook existe dans l'API iThenticate (id : {$webhookId}, url : {$url}) mais n'est PAS dans la base de données. Utilisez 'update --include-api' pour supprimer et réenregistrer, ou 'delete --include-api' pour le retirer." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Aucun webhook trouvé dans l'API iThenticate pour les identifiants fournis." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Un webhook existe déjà dans l'API iThenticate avec l'id : {$webhookId} pour l'URL : {$url}. Utilisez 'update --include-api' pour le remplacer." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Aucun webhook trouvé dans la base de données pour ce contexte. Utilisez --include-api pour vérifier également dans l'API iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Le webhook {$webhookId} n'a pas été trouvé dans l'API iThenticate (il a peut-être déjà été supprimé). Nettoyage de l'enregistrement local de la base de données." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Le webhook supprimé {$deletedId} diffère de l'enregistrement de la base de données ({$dbId}). L'enregistrement de la base de données a été conservé." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Incohérence d'ID de webhook : la base de données contient {$dbId} mais l'API iThenticate contient {$apiId} pour l'URL {$url}. Utilisez 'update --include-api' pour résoudre." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Note : Le webhook validé {$validatedId} (depuis l'API) diffère de l'enregistrement de la base de données ({$dbId})." diff --git a/locale/gl/locale.po b/locale/gl/locale.po index c4ed21cb..d81b16d9 100644 --- a/locale/gl/locale.po +++ b/locale/gl/locale.po @@ -93,3 +93,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Eliminar o webhook para a conta iThenticate para unha ruta de contexto dada" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Requírense as credenciais da API. Proporcione --api-url e --api-key, ou --context para usar as credenciais almacenadas." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Non se atopou ningún webhook na API de iThenticate para este contexto. Nada que eliminar." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Existe un webhook na API de iThenticate (id: {$webhookId}, url: {$url}) pero NON está na base de datos. Use 'update --include-api' para eliminar e rexistrar de novo, ou 'delete --include-api' para eliminalo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Non se atoparon webhooks na API de iThenticate para as credenciais proporcionadas." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Xa existe un webhook na API de iThenticate co id: {$webhookId} para o URL: {$url}. Use 'update --include-api' para substituílo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Non se atopou ningún webhook na base de datos para este contexto. Use --include-api para comprobar tamén na API de iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "O webhook {$webhookId} non se atopou na API de iThenticate (pode que xa fose eliminado). Limpando o rexistro local da base de datos." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "O webhook eliminado {$deletedId} difire do rexistro da base de datos ({$dbId}). O rexistro da base de datos conservouse." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Discrepancia de ID de webhook: a base de datos ten {$dbId} pero a API de iThenticate ten {$apiId} para o URL {$url}. Use 'update --include-api' para resolver." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Nota: O webhook validado {$validatedId} (da API) difire do rexistro da base de datos ({$dbId})." diff --git a/locale/hy/locale.po b/locale/hy/locale.po index 5b5c251c..7ef8178a 100644 --- a/locale/hy/locale.po +++ b/locale/hy/locale.po @@ -406,3 +406,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Delete the webhook for iThenticate account for a given context path" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "API credentials required. Provide --api-url and --api-key, or --context to use stored credentials." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "No webhook found at iThenticate API for this context. Nothing to delete." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook exists at iThenticate API (id: {$webhookId}, url: {$url}) but is NOT in the database. Use 'update --include-api' to delete and re-register, or 'delete --include-api' to remove it." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "No webhooks found at iThenticate API for the provided credentials." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "A webhook already exists at iThenticate API with id: {$webhookId} for URL: {$url}. Use 'update --include-api' to replace it." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "No webhook found in the database for this context. Use --include-api to also check the iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} was not found at iThenticate API (may have been deleted already). Cleaning up local database record." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Deleted webhook {$deletedId} differs from the database record ({$dbId}). Database record preserved." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Webhook ID mismatch: database has {$dbId} but iThenticate API has {$apiId} for URL {$url}. Use 'update --include-api' to resolve." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Note: Validated webhook {$validatedId} (from API) differs from database record ({$dbId})." diff --git a/locale/id/locale.po b/locale/id/locale.po index c01e907b..25e53667 100644 --- a/locale/id/locale.po +++ b/locale/id/locale.po @@ -382,3 +382,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Hapus webhook untuk akun iThenticate pada jalur konteks tertentu" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Kredensial API diperlukan. Berikan --api-url dan --api-key, atau --context untuk menggunakan kredensial yang tersimpan." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Tidak ditemukan webhook di API iThenticate untuk konteks ini. Tidak ada yang perlu dihapus." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook ditemukan di API iThenticate (id: {$webhookId}, url: {$url}) tetapi TIDAK ada di database. Gunakan 'update --include-api' untuk menghapus dan mendaftar ulang, atau 'delete --include-api' untuk menghapusnya." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Tidak ditemukan webhook di API iThenticate untuk kredensial yang diberikan." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Webhook sudah ada di API iThenticate dengan id: {$webhookId} untuk URL: {$url}. Gunakan 'update --include-api' untuk menggantinya." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Tidak ditemukan webhook di database untuk konteks ini. Gunakan --include-api untuk juga memeriksa API iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} tidak ditemukan di API iThenticate (mungkin sudah dihapus sebelumnya). Membersihkan catatan database lokal." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Webhook yang dihapus {$deletedId} berbeda dari catatan database ({$dbId}). Catatan database dipertahankan." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Ketidakcocokan ID webhook: database memiliki {$dbId} tetapi API iThenticate memiliki {$apiId} untuk URL {$url}. Gunakan 'update --include-api' untuk menyelesaikannya." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Catatan: Webhook yang divalidasi {$validatedId} (dari API) berbeda dari catatan database ({$dbId})." diff --git a/locale/it/locale.po b/locale/it/locale.po index 36c806ca..d5643323 100644 --- a/locale/it/locale.po +++ b/locale/it/locale.po @@ -119,3 +119,47 @@ msgstr "Webhook iThenticate con ID: {$webhookId} eliminato con successo per cont #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Impossibile eliminare il webhook iThenticate con ID: {$webhookId} per contesto ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Elimina il webhook per l'account iThenticate per un percorso di contesto specificato" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Credenziali API obbligatorie. Fornire --api-url e --api-key, oppure --context per utilizzare le credenziali memorizzate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Nessun webhook trovato nell'API iThenticate per questo contesto. Nulla da eliminare." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Il webhook esiste nell'API iThenticate (id: {$webhookId}, url: {$url}) ma NON è presente nel database. Usa 'update --include-api' per eliminare e ri-registrare, oppure 'delete --include-api' per rimuoverlo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Nessun webhook trovato nell'API iThenticate per le credenziali fornite." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Un webhook esiste già nell'API iThenticate con id: {$webhookId} per l'URL: {$url}. Usa 'update --include-api' per sostituirlo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Nessun webhook trovato nel database per questo contesto. Usa --include-api per verificare anche l'API iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Il webhook {$webhookId} non è stato trovato nell'API iThenticate (potrebbe essere già stato eliminato). Pulizia del record nel database locale." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Il webhook eliminato {$deletedId} differisce dal record nel database ({$dbId}). Il record nel database è stato preservato." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Discrepanza ID webhook: il database ha {$dbId} ma l'API iThenticate ha {$apiId} per l'URL {$url}. Usa 'update --include-api' per risolvere." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Nota: il webhook validato {$validatedId} (dall'API) differisce dal record nel database ({$dbId})." diff --git a/locale/ja/locale.po b/locale/ja/locale.po index b221f070..09cac826 100644 --- a/locale/ja/locale.po +++ b/locale/ja/locale.po @@ -1,3 +1,47 @@ # Bjorn-Ole Kamm , 2024. msgid "" msgstr "X-Generator: Weblate\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "指定されたコンテキストパスのiThenticateアカウントのWebhookを削除します" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "API資格情報が必要です。--api-urlと--api-keyを指定するか、--contextを使用して保存された資格情報を使用してください。" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "このコンテキストのiThenticate APIにWebhookが見つかりません。削除するものはありません。" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "iThenticate APIにWebhookが存在します(id: {$webhookId}、url: {$url})が、データベースには存在しません。'update --include-api'を使用して削除して再登録するか、'delete --include-api'を使用して削除してください。" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "指定された資格情報のiThenticate APIにWebhookが見つかりません。" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "iThenticate APIにid: {$webhookId}のWebhookがURL: {$url}で既に存在します。'update --include-api'を使用して置き換えてください。" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "このコンテキストのデータベースにWebhookが見つかりません。--include-apiを使用してiThenticate APIも確認してください。" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId}がiThenticate APIで見つかりませんでした(既に削除されている可能性があります)。ローカルデータベースレコードをクリーンアップしています。" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "削除されたWebhook {$deletedId}はデータベースレコード({$dbId})と異なります。データベースレコードは保持されました。" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Webhook IDの不一致: データベースには{$dbId}がありますが、iThenticate APIにはURL {$url}に対して{$apiId}があります。'update --include-api'を使用して解決してください。" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "注: 検証済みWebhook {$validatedId}(APIから)はデータベースレコード({$dbId})と異なります。" diff --git a/locale/ka/locale.po b/locale/ka/locale.po index 620a9f75..9c78e353 100644 --- a/locale/ka/locale.po +++ b/locale/ka/locale.po @@ -93,3 +93,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "მითითებული კონტექსტის ბილიკისთვის iThenticate ანგარიშის webhook-ის წაშლა" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "საჭიროა API სერთიფიკატები. მიუთითეთ --api-url და --api-key, ან --context შენახული სერთიფიკატების გამოსაყენებლად." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "ამ კონტექსტისთვის iThenticate API-ში webhook ვერ მოიძებნა. წასაშლელი არაფერია." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook არსებობს iThenticate API-ში (id: {$webhookId}, url: {$url}), მაგრამ არ არის მონაცემთა ბაზაში. გამოიყენეთ 'update --include-api' წასაშლელად და ხელახლა დასარეგისტრირებლად, ან 'delete --include-api' მის მოსაშორებლად." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "მოწოდებული სერთიფიკატებისთვის iThenticate API-ში webhook-ები ვერ მოიძებნა." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Webhook უკვე არსებობს iThenticate API-ში id: {$webhookId} URL-ისთვის: {$url}. გამოიყენეთ 'update --include-api' მის ჩასანაცვლებლად." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "ამ კონტექსტისთვის მონაცემთა ბაზაში webhook ვერ მოიძებნა. გამოიყენეთ --include-api iThenticate API-ის შესამოწმებლადაც." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} ვერ მოიძებნა iThenticate API-ში (შესაძლოა უკვე წაშლილია). ლოკალური მონაცემთა ბაზის ჩანაწერის გასუფთავება." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "წაშლილი webhook {$deletedId} განსხვავდება მონაცემთა ბაზის ჩანაწერისგან ({$dbId}). მონაცემთა ბაზის ჩანაწერი შენარჩუნებულია." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Webhook ID-ის შეუსაბამობა: მონაცემთა ბაზაში არის {$dbId}, მაგრამ iThenticate API-ში არის {$apiId} URL-ისთვის {$url}. გამოიყენეთ 'update --include-api' პრობლემის მოსაგვარებლად." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "შენიშვნა: დამოწმებული webhook {$validatedId} (API-დან) განსხვავდება მონაცემთა ბაზის ჩანაწერისგან ({$dbId})." diff --git a/locale/ky/locale.po b/locale/ky/locale.po index 54f540fe..0a8e2030 100644 --- a/locale/ky/locale.po +++ b/locale/ky/locale.po @@ -376,3 +376,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Берилген контекст жолу үчүн iThenticate аккаунтунун вебхугун жок кылуу" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "API маалыматтары талап кылынат. --api-url жана --api-key көрсөтүңүз, же сакталган маалыматтарды колдонуу үчүн --context колдонуңуз." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Бул контекст үчүн iThenticate API'де вебхук табылган жок. Жок кыла турган эч нерсе жок." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Вебхук iThenticate API'де бар (id: {$webhookId}, url: {$url}), бирок маалымат базасында ЖОК. Жок кылуу жана кайра каттоо үчүн 'update --include-api' колдонуңуз, же аны алып салуу үчүн 'delete --include-api' колдонуңуз." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Берилген маалыматтар үчүн iThenticate API'де вебхуктар табылган жок." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "iThenticate API'де id: {$webhookId} менен вебхук URL: {$url} үчүн мурунтан эле бар. Аны алмаштыруу үчүн 'update --include-api' колдонуңуз." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Бул контекст үчүн маалымат базасында вебхук табылган жок. iThenticate API'ни да текшерүү үчүн --include-api колдонуңуз." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Вебхук {$webhookId} iThenticate API'де табылган жок (мурунтан эле жок кылынган болушу мүмкүн). Жергиликтүү маалымат базасынын жазуусу тазаланууда." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Жок кылынган вебхук {$deletedId} маалымат базасынын жазуусунан ({$dbId}) айырмаланат. Маалымат базасынын жазуусу сакталды." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Вебхук ID дал келбестиги: маалымат базасында {$dbId} бар, бирок iThenticate API'де URL {$url} үчүн {$apiId} бар. Чечүү үчүн 'update --include-api' колдонуңуз." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Эскертүү: Текшерилген вебхук {$validatedId} (API'ден) маалымат базасынын жазуусунан ({$dbId}) айырмаланат." diff --git a/locale/mk/locale.po b/locale/mk/locale.po index aeaf4bd2..3fc3361b 100644 --- a/locale/mk/locale.po +++ b/locale/mk/locale.po @@ -387,3 +387,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Избриши го webhook за iThenticate сметката за дадената патека на контекст" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Потребни се API акредитиви. Обезбедете --api-url и --api-key, или --context за да ги користите зачуваните акредитиви." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Не е пронајден webhook на iThenticate API за овој контекст. Нема што да се избрише." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook постои на iThenticate API (id: {$webhookId}, url: {$url}) но НЕ е во базата на податоци. Користете 'update --include-api' за да го избришете и повторно регистрирате, или 'delete --include-api' за да го отстраните." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Не се пронајдени webhook-ови на iThenticate API за дадените акредитиви." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Webhook веќе постои на iThenticate API со id: {$webhookId} за URL: {$url}. Користете 'update --include-api' за да го замените." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Не е пронајден webhook во базата на податоци за овој контекст. Користете --include-api за да го проверите и iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} не е пронајден на iThenticate API (можеби е веќе избришан). Чистење на локалниот запис во базата на податоци." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Избришаниот webhook {$deletedId} се разликува од записот во базата на податоци ({$dbId}). Записот во базата на податоци е зачуван." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Несовпаѓање на Webhook ID: базата на податоци има {$dbId} но iThenticate API има {$apiId} за URL {$url}. Користете 'update --include-api' за да го решите." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Забелешка: Валидираниот webhook {$validatedId} (од API) се разликува од записот во базата на податоци ({$dbId})." diff --git a/locale/ms/locale.po b/locale/ms/locale.po index 7830fbd2..2b1ca1c0 100644 --- a/locale/ms/locale.po +++ b/locale/ms/locale.po @@ -95,3 +95,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Padam webhook untuk akaun iThenticate bagi laluan konteks yang diberikan" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Kelayakan API diperlukan. Sediakan --api-url dan --api-key, atau --context untuk menggunakan kelayakan yang tersimpan." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Tiada webhook ditemui di API iThenticate untuk konteks ini. Tiada apa untuk dipadam." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook wujud di API iThenticate (id: {$webhookId}, url: {$url}) tetapi TIDAK ada dalam pangkalan data. Gunakan 'update --include-api' untuk memadam dan mendaftar semula, atau 'delete --include-api' untuk membuangnya." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Tiada webhook ditemui di API iThenticate untuk kelayakan yang diberikan." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Webhook sudah wujud di API iThenticate dengan id: {$webhookId} untuk URL: {$url}. Gunakan 'update --include-api' untuk menggantikannya." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Tiada webhook ditemui dalam pangkalan data untuk konteks ini. Gunakan --include-api untuk turut menyemak API iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} tidak ditemui di API iThenticate (mungkin telah dipadam). Membersihkan rekod pangkalan data tempatan." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Webhook yang dipadam {$deletedId} berbeza daripada rekod pangkalan data ({$dbId}). Rekod pangkalan data dikekalkan." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Ketidakpadanan ID webhook: pangkalan data mempunyai {$dbId} tetapi API iThenticate mempunyai {$apiId} untuk URL {$url}. Gunakan 'update --include-api' untuk menyelesaikan." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Nota: Webhook yang disahkan {$validatedId} (dari API) berbeza daripada rekod pangkalan data ({$dbId})." diff --git a/locale/nb/locale.po b/locale/nb/locale.po index 5da341e2..575440cc 100644 --- a/locale/nb/locale.po +++ b/locale/nb/locale.po @@ -91,3 +91,47 @@ msgstr "" msgid "plugins.generic.plagiarism.ithenticate.submission.error.PROCESSING_ERROR" msgstr "Det oppsto en uspesifisert feil under behandling av innleveringen." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Slett webhooken for iThenticate-kontoen for en gitt kontekststi" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "API-legitimasjon er påkrevd. Oppgi --api-url og --api-key, eller --context for å bruke lagret legitimasjon." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Ingen webhook funnet hos iThenticate API for denne konteksten. Ingenting å slette." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook eksisterer hos iThenticate API (id: {$webhookId}, url: {$url}), men er IKKE i databasen. Bruk 'update --include-api' for å slette og registrere på nytt, eller 'delete --include-api' for å fjerne den." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Ingen webhooks funnet hos iThenticate API for oppgitt legitimasjon." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "En webhook eksisterer allerede hos iThenticate API med id: {$webhookId} for URL: {$url}. Bruk 'update --include-api' for å erstatte den." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Ingen webhook funnet i databasen for denne konteksten. Bruk --include-api for også å sjekke iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} ble ikke funnet hos iThenticate API (kan allerede ha blitt slettet). Rydder opp i lokal databasepost." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Slettet webhook {$deletedId} avviker fra databaseposten ({$dbId}). Databaseposten er bevart." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Webhook-ID-avvik: databasen har {$dbId}, men iThenticate API har {$apiId} for URL {$url}. Bruk 'update --include-api' for å løse dette." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Merk: Validert webhook {$validatedId} (fra API) avviker fra databaseposten ({$dbId})." diff --git a/locale/pt/locale.po b/locale/pt/locale.po index d5adedbe..fae97331 100644 --- a/locale/pt/locale.po +++ b/locale/pt/locale.po @@ -6,3 +6,47 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Weblate\n" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Eliminar o webhook da conta iThenticate para um caminho de contexto indicado" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Credenciais da API necessárias. Forneça --api-url e --api-key, ou --context para utilizar credenciais armazenadas." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Nenhum webhook encontrado na API do iThenticate para este contexto. Nada a eliminar." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "O webhook existe na API do iThenticate (id: {$webhookId}, url: {$url}), mas NÃO está na base de dados. Utilize 'update --include-api' para eliminar e registar novamente, ou 'delete --include-api' para o remover." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Nenhum webhook encontrado na API do iThenticate para as credenciais fornecidas." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Já existe um webhook na API do iThenticate com id: {$webhookId} para o URL: {$url}. Utilize 'update --include-api' para o substituir." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Nenhum webhook encontrado na base de dados para este contexto. Utilize --include-api para verificar também a API do iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "O webhook {$webhookId} não foi encontrado na API do iThenticate (pode já ter sido eliminado). A limpar o registo local da base de dados." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "O webhook eliminado {$deletedId} difere do registo na base de dados ({$dbId}). O registo da base de dados foi preservado." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Incompatibilidade de ID do webhook: a base de dados tem {$dbId}, mas a API do iThenticate tem {$apiId} para o URL {$url}. Utilize 'update --include-api' para resolver." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Nota: O webhook validado {$validatedId} (da API) difere do registo na base de dados ({$dbId})." diff --git a/locale/pt_BR/locale.po b/locale/pt_BR/locale.po index 35f72e60..fac588da 100644 --- a/locale/pt_BR/locale.po +++ b/locale/pt_BR/locale.po @@ -406,3 +406,47 @@ msgstr "Webhook iThenticate com ID: {$webhookId} excluído com sucesso para cont #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Não foi possível excluir o webhook iThenticate com ID: {$webhookId} para contexto ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Excluir o webhook da conta iThenticate para um caminho de contexto fornecido" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Credenciais da API são obrigatórias. Forneça --api-url e --api-key, ou --context para usar credenciais armazenadas." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Nenhum webhook encontrado na API do iThenticate para este contexto. Nada a excluir." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook existe na API do iThenticate (id: {$webhookId}, url: {$url}), mas NÃO está no banco de dados. Use 'update --include-api' para excluir e registrar novamente, ou 'delete --include-api' para removê-lo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Nenhum webhook encontrado na API do iThenticate para as credenciais fornecidas." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Um webhook já existe na API do iThenticate com id: {$webhookId} para URL: {$url}. Use 'update --include-api' para substituí-lo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Nenhum webhook encontrado no banco de dados para este contexto. Use --include-api para verificar também a API do iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} não foi encontrado na API do iThenticate (pode já ter sido excluído). Limpando registro local do banco de dados." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "O webhook excluído {$deletedId} difere do registro no banco de dados ({$dbId}). Registro do banco de dados preservado." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Incompatibilidade de ID do webhook: banco de dados tem {$dbId}, mas a API do iThenticate tem {$apiId} para URL {$url}. Use 'update --include-api' para resolver." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Nota: Webhook validado {$validatedId} (da API) difere do registro no banco de dados ({$dbId})." diff --git a/locale/ru/locale.po b/locale/ru/locale.po index b6fc2310..bc64ad64 100644 --- a/locale/ru/locale.po +++ b/locale/ru/locale.po @@ -118,3 +118,47 @@ msgstr "Успешно удален вебхук iThenticate с ID: {$webhookId} #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Невозможно удалить вебхук iThenticate с ID: {$webhookId} для контекста ID: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Удалить вебхук для учетной записи iThenticate для указанного пути контекста" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Необходимы учетные данные API. Укажите --api-url и --api-key, или --context для использования сохраненных учетных данных." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Вебхук не найден в API iThenticate для данного контекста. Нечего удалять." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Вебхук существует в API iThenticate (id: {$webhookId}, url: {$url}), но НЕ найден в базе данных. Используйте 'update --include-api' для удаления и повторной регистрации, или 'delete --include-api' для его удаления." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Вебхуки не найдены в API iThenticate для указанных учетных данных." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Вебхук уже существует в API iThenticate с id: {$webhookId} для URL: {$url}. Используйте 'update --include-api' для его замены." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Вебхук не найден в базе данных для данного контекста. Используйте --include-api для дополнительной проверки API iThenticate." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Вебхук {$webhookId} не найден в API iThenticate (возможно, уже был удален). Очистка локальной записи в базе данных." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Удаленный вебхук {$deletedId} отличается от записи в базе данных ({$dbId}). Запись в базе данных сохранена." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Несоответствие ID вебхука: в базе данных {$dbId}, но в API iThenticate {$apiId} для URL {$url}. Используйте 'update --include-api' для разрешения." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Примечание: Проверенный вебхук {$validatedId} (из API) отличается от записи в базе данных ({$dbId})." diff --git a/locale/sl/locale.po b/locale/sl/locale.po index c31cd158..92e57f13 100644 --- a/locale/sl/locale.po +++ b/locale/sl/locale.po @@ -381,3 +381,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Izbriši webhook za iThenticate račun za dano kontekstno pot" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Zahtevane so poverilnice API. Navedite --api-url in --api-key ali --context za uporabo shranjenih poverilnic." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Za ta kontekst ni bilo najdenih webhookov na iThenticate API. Ni kaj za izbrisati." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook obstaja na iThenticate API (id: {$webhookId}, url: {$url}), vendar NI v podatkovni bazi. Uporabite 'update --include-api' za izbris in ponovno registracijo ali 'delete --include-api' za odstranitev." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Za podane poverilnice ni bilo najdenih webhookov na iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Webhook že obstaja na iThenticate API z id: {$webhookId} za URL: {$url}. Uporabite 'update --include-api' za zamenjavo." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "V podatkovni bazi za ta kontekst ni bilo najdenega webhooka. Uporabite --include-api za preverjanje tudi na iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} ni bil najden na iThenticate API (morda je bil že izbrisan). Čiščenje lokalnega zapisa v podatkovni bazi." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Izbrisan webhook {$deletedId} se razlikuje od zapisa v podatkovni bazi ({$dbId}). Zapis v podatkovni bazi je ohranjen." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Neskladje ID webhooka: podatkovni bazi ima {$dbId}, vendar iThenticate API ima {$apiId} za URL {$url}. Uporabite 'update --include-api' za razrešitev." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Opomba: Preverjen webhook {$validatedId} (iz API) se razlikuje od zapisa v podatkovni bazi ({$dbId})." diff --git a/locale/sv/locale.po b/locale/sv/locale.po index ea68fc0a..6980d570 100644 --- a/locale/sv/locale.po +++ b/locale/sv/locale.po @@ -92,3 +92,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Ta bort webhooken för iThenticate-kontot för en given kontextsökväg" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "API-autentiseringsuppgifter krävs. Ange --api-url och --api-key, eller --context för att använda lagrade autentiseringsuppgifter." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Ingen webhook hittades hos iThenticate API för denna kontext. Inget att ta bort." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook finns hos iThenticate API (id: {$webhookId}, url: {$url}) men finns INTE i databasen. Använd 'update --include-api' för att ta bort och omregistrera, eller 'delete --include-api' för att ta bort den." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Inga webhooks hittades hos iThenticate API för de angivna autentiseringsuppgifterna." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "En webhook finns redan hos iThenticate API med id: {$webhookId} för URL: {$url}. Använd 'update --include-api' för att ersätta den." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Ingen webhook hittades i databasen för denna kontext. Använd --include-api för att även kontrollera iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Webhook {$webhookId} hittades inte hos iThenticate API (kan redan ha tagits bort). Rensar lokal databaspost." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Borttagen webhook {$deletedId} skiljer sig från databasposten ({$dbId}). Databasposten bevaras." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Webhook-ID stämmer inte överens: databasen har {$dbId} men iThenticate API har {$apiId} för URL {$url}. Använd 'update --include-api' för att lösa detta." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Observera: Validerad webhook {$validatedId} (från API) skiljer sig från databasposten ({$dbId})." diff --git a/locale/tr/locale.po b/locale/tr/locale.po index 5397c56e..9ac0cbe8 100644 --- a/locale/tr/locale.po +++ b/locale/tr/locale.po @@ -395,3 +395,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Belirtilen bağlam yolu için iThenticate hesabına ait web kancasını sil" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "API kimlik bilgileri gereklidir. --api-url ve --api-key sağlayın veya kayıtlı kimlik bilgilerini kullanmak için --context belirtin." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Bu bağlam için iThenticate API'sinde web kancası bulunamadı. Silinecek bir şey yok." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Web kancası iThenticate API'sinde mevcut (id: {$webhookId}, url: {$url}) ancak veritabanında YOKTUR. Silip yeniden kaydetmek için 'update --include-api' veya kaldırmak için 'delete --include-api' kullanın." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Sağlanan kimlik bilgileri için iThenticate API'sinde web kancası bulunamadı." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "iThenticate API'sinde şu id ile zaten bir web kancası mevcut: {$webhookId}, URL: {$url}. Değiştirmek için 'update --include-api' kullanın." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Bu bağlam için veritabanında web kancası bulunamadı. iThenticate API'sini de kontrol etmek için --include-api kullanın." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Web kancası {$webhookId} iThenticate API'sinde bulunamadı (daha önce silinmiş olabilir). Yerel veritabanı kaydı temizleniyor." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Silinen web kancası {$deletedId}, veritabanı kaydından ({$dbId}) farklıdır. Veritabanı kaydı korundu." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Web kancası ID uyumsuzluğu: veritabanında {$dbId} var ancak iThenticate API'sinde {$url} URL'si için {$apiId} var. Çözmek için 'update --include-api' kullanın." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Not: Doğrulanan web kancası {$validatedId} (API'den), veritabanı kaydından ({$dbId}) farklıdır." diff --git a/locale/uk/locale.po b/locale/uk/locale.po index 46792829..8540f91d 100644 --- a/locale/uk/locale.po +++ b/locale/uk/locale.po @@ -376,3 +376,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Видалити вебхук для облікового запису iThenticate для заданого шляху контексту" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Потрібні облікові дані API. Вкажіть --api-url та --api-key або --context для використання збережених облікових даних." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Вебхук не знайдено в iThenticate API для цього контексту. Нічого видаляти." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Вебхук існує в iThenticate API (id: {$webhookId}, url: {$url}), але його НЕМАЄ в базі даних. Використайте 'update --include-api' для видалення та повторної реєстрації або 'delete --include-api' для його вилучення." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Вебхуки не знайдено в iThenticate API для наданих облікових даних." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Вебхук уже існує в iThenticate API з id: {$webhookId} для URL: {$url}. Використайте 'update --include-api' для його заміни." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Вебхук не знайдено в базі даних для цього контексту. Використайте --include-api для перевірки також в iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Вебхук {$webhookId} не знайдено в iThenticate API (можливо, його вже було видалено). Очищення локального запису в базі даних." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Видалений вебхук {$deletedId} відрізняється від запису в базі даних ({$dbId}). Запис у базі даних збережено." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "Невідповідність ID вебхука: у базі даних {$dbId}, але в iThenticate API {$apiId} для URL {$url}. Використайте 'update --include-api' для вирішення." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Примітка: Перевірений вебхук {$validatedId} (з API) відрізняється від запису в базі даних ({$dbId})." diff --git a/locale/vi/locale.po b/locale/vi/locale.po index 1c1fd3e3..5272626a 100644 --- a/locale/vi/locale.po +++ b/locale/vi/locale.po @@ -93,3 +93,47 @@ msgstr "Successfully deleted the iThenticate webhook with id: {$webhookId} for c #, fuzzy msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error" msgstr "Unable to delete the iThenticate webhook with id: {$webhookId} for context id: {$contextId}" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.delete.description" +msgstr "Xoá webhook cho tài khoản iThenticate theo đường dẫn ngữ cảnh đã cho" + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing" +msgstr "Yêu cầu thông tin xác thực API. Cung cấp --api-url và --api-key, hoặc --context để sử dụng thông tin xác thực đã lưu." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete" +msgstr "Không tìm thấy webhook nào trên iThenticate API cho ngữ cảnh này. Không có gì để xoá." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned" +msgstr "Webhook tồn tại trên iThenticate API (id: {$webhookId}, url: {$url}) nhưng KHÔNG có trong cơ sở dữ liệu. Sử dụng 'update --include-api' để xoá và đăng ký lại, hoặc 'delete --include-api' để gỡ bỏ." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty" +msgstr "Không tìm thấy webhook nào trên iThenticate API cho thông tin xác thực đã cung cấp." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.alreadyExists" +msgstr "Webhook đã tồn tại trên iThenticate API với id: {$webhookId} cho URL: {$url}. Sử dụng 'update --include-api' để thay thế." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete" +msgstr "Không tìm thấy webhook nào trong cơ sở dữ liệu cho ngữ cảnh này. Sử dụng --include-api để kiểm tra cả iThenticate API." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi" +msgstr "Không tìm thấy webhook {$webhookId} trên iThenticate API (có thể đã bị xoá trước đó). Đang dọn dẹp bản ghi cơ sở dữ liệu cục bộ." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved" +msgstr "Webhook đã xoá {$deletedId} khác với bản ghi cơ sở dữ liệu ({$dbId}). Bản ghi cơ sở dữ liệu được giữ nguyên." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch" +msgstr "ID webhook không khớp: cơ sở dữ liệu có {$dbId} nhưng iThenticate API có {$apiId} cho URL {$url}. Sử dụng 'update --include-api' để giải quyết." + +#, fuzzy +msgid "plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch" +msgstr "Lưu ý: Webhook đã xác thực {$validatedId} (từ API) khác với bản ghi cơ sở dữ liệu ({$dbId})." diff --git a/tools/webhook.php b/tools/webhook.php index f516a6bc..2f17123c 100644 --- a/tools/webhook.php +++ b/tools/webhook.php @@ -6,7 +6,7 @@ * Copyright (c) 2025 Simon Fraser University * Copyright (c) 2025 John Willinsky * Distributed under the GNU GPL v3. For full terms see the file LICENSE. - * + * * @class RegisterWebhooks * * @brief CLI tools to update iThenticate webhooks for all Journals/Presses/Servers @@ -67,13 +67,14 @@ public function errorBlock(array $messages = [], ?string $title = null): void class Webhook extends CommandLineTool { public const REACHABILITY_TIMEOUT = 10; - + protected const AVAILABLE_OPTIONS = [ - 'register' => 'plugins.generic.plagiarism.tools.registerWebhooks.register.description', - 'update' => 'plugins.generic.plagiarism.tools.registerWebhooks.update.description', - 'validate' => 'plugins.generic.plagiarism.tools.registerWebhooks.validate.description', - 'list' => 'plugins.generic.plagiarism.tools.registerWebhooks.list.description', - 'usage' => 'plugins.generic.plagiarism.tools.registerWebhooks.usage.description', + 'register' => 'plugins.generic.plagiarism.tools.registerWebhooks.register.description', + 'update' => 'plugins.generic.plagiarism.tools.registerWebhooks.update.description', + 'delete' => 'plugins.generic.plagiarism.tools.registerWebhooks.delete.description', + 'validate' => 'plugins.generic.plagiarism.tools.registerWebhooks.validate.description', + 'list' => 'plugins.generic.plagiarism.tools.registerWebhooks.list.description', + 'usage' => 'plugins.generic.plagiarism.tools.registerWebhooks.usage.description', ]; /** @@ -108,7 +109,7 @@ class Webhook extends CommandLineTool /** * Constructor. - * + * * @param array $argv command-line arguments */ public function __construct($argv = []) @@ -192,6 +193,14 @@ protected function getParameterValue(string $parameter, mixed $default = null): return $this->getParameterList()[$parameter]; } + /** + * Check if a CLI flag is set (e.g. --force, --include-api) + */ + protected function hasFlagSet(string $flag): bool + { + return in_array($flag, $this->getParameterList()); + } + /** * Print given options in a pretty way. */ @@ -241,18 +250,47 @@ public function execute() ); } - if (in_array($this->option, ['register', 'update', 'validate'])) { - if (!$this->validateRequiredParameters()) { - throw new CommandNotFoundException( - __( - 'plugins.generic.plagiarism.tools.registerWebhooks.required.parameters.missing', - ['parameter' => 'context', 'command' => $this->option] - ), - [__('plugins.generic.plagiarism.tools.registerWebhooks.required.parameters.missing.example', ['command' => $this->option])] - ); - } + $isIncludeApi = $this->isIncludeApi(); + $hasExplicitCreds = $this->hasExplicitApiCredentials(); + $hasContext = $this->getParameterValue('context') !== null; + $hasWebhookId = $this->getParameterValue('webhook-id') !== null; + + // Commands that ALWAYS need --context + $alwaysNeedContext = ['register', 'update']; + + // Commands that need --context UNLESS --include-api with explicit creds + webhook-id + $conditionalContext = ['delete', 'validate']; + + // Determine if context is required + $contextRequired = false; + if (in_array($this->option, $alwaysNeedContext)) { + $contextRequired = true; + } elseif (in_array($this->option, $conditionalContext)) { + $contextRequired = !($isIncludeApi && $hasExplicitCreds && $hasWebhookId); + } elseif ($this->option === 'list' && $isIncludeApi) { + $contextRequired = !$hasExplicitCreds; + } + + if ($contextRequired && !$hasContext) { + throw new CommandNotFoundException( + __( + 'plugins.generic.plagiarism.tools.registerWebhooks.required.parameters.missing', + ['parameter' => 'context', 'command' => $this->option] + ), + [__('plugins.generic.plagiarism.tools.registerWebhooks.required.parameters.missing.example', ['command' => $this->option])] + ); + } + // Load context if provided + if ($hasContext) { $this->context = $this->getContext(); + } + + // Determine if API access is needed + $needsApi = in_array($this->option, ['register', 'update', 'delete', 'validate']) + || ($this->option === 'list' && $isIncludeApi); + + if ($needsApi) { $this->plagiarismPlugin = new PlagiarismPlugin(); $this->initIthenticate(); } @@ -260,6 +298,56 @@ public function execute() $this->{$this->option}(); } + /** + * Check if the --include-api flag is set + */ + protected function isIncludeApi(): bool + { + return $this->hasFlagSet('--include-api'); + } + + /** + * Check if explicit API credentials are provided via --api-url and --api-key + */ + protected function hasExplicitApiCredentials(): bool + { + return $this->getParameterValue('api-url') !== null + && $this->getParameterValue('api-key') !== null; + } + + /** + * Resolve the webhook ID for the current context + * + * Uses a tiered approach: + * 1. Explicit --webhook-id parameter (highest priority) + * 2. If --include-api and context available, find by URL at API + * 3. Fall back to DB-stored webhook ID + */ + protected function findWebhookIdForContext(): ?string + { + // 1. Explicit --webhook-id always wins + $explicitWebhookId = $this->getParameterValue('webhook-id'); + if ($explicitWebhookId) { + return $explicitWebhookId; + } + + // 2. If --include-api and context available, find by URL at API + if ($this->isIncludeApi() && isset($this->context)) { + $webhookUrl = $this->plagiarismPlugin->getWebhookUrl($this->context); + $apiWebhookId = $this->ithenticate->findWebhookIdByUrl($webhookUrl); + if ($apiWebhookId) { + return $apiWebhookId; + } + } + + // 3. Fall back to DB + if (isset($this->context)) { + return $this->context->getData('ithenticateWebhookId'); + } + + return null; + } + /** * Get the context for given context path or id */ @@ -267,10 +355,10 @@ protected function getContext(): Context { $contextPathOrId = $this->getParameterValue('context'); $contextDao = Application::getContextDAO(); /** @var ContextDAO $contextDao */ - + /** @var Context $context */ $context = $contextDao->getByPath((string)$contextPathOrId) ?? $contextDao->getById((int)$contextPathOrId); - + if (!$context) { throw new CommandInvalidArgumentException( __( @@ -299,7 +387,7 @@ protected function validateRequiredParameters(): bool * Get plugin version from version.xml file * * @return string The plugin version from the release tag - * + * * @throws Exception If the version.xml file is not found or cannot be read */ protected function getPluginVersion(): ?string @@ -341,17 +429,32 @@ protected function getPluginVersion(): ?string /** * Initialize the iThenticate service + * + * Supports both explicit credentials (--api-url/--api-key) and context-based credentials. + * Explicit credentials take priority when provided. */ protected function initIthenticate(): void { - if (!$this->plagiarismPlugin->isServiceAccessAvailable($this->context)) { - throw new CommandInvalidArgumentException( - __('plugins.generic.plagiarism.manager.settings.serviceAccessMissing') - ); - } + $apiUrl = $this->getParameterValue('api-url'); + $apiKey = $this->getParameterValue('api-key'); + + // If explicit creds not provided, get from context + if (!$apiUrl || !$apiKey) { + if (!isset($this->context)) { + throw new CommandInvalidArgumentException( + __('plugins.generic.plagiarism.tools.registerWebhooks.credentials.missing') + ); + } - // Get service access credentials - list($apiUrl, $apiKey) = $this->plagiarismPlugin->getServiceAccess($this->context); + if (!$this->plagiarismPlugin->isServiceAccessAvailable($this->context)) { + throw new CommandInvalidArgumentException( + __('plugins.generic.plagiarism.manager.settings.serviceAccessMissing') + ); + } + + // Get service access credentials + list($apiUrl, $apiKey) = $this->plagiarismPlugin->getServiceAccess($this->context); + } // Get plugin version from version.xml for CLI context $pluginVersion = $this->getPluginVersion(); @@ -371,45 +474,141 @@ protected function initIthenticate(): void } } + /** + * Display the full API response details for debugging + * + * @param string|null $errorMessage Optional custom error message to display + */ + protected function displayApiResponseDetails(?string $errorMessage = null): void + { + $errorMessage ??= __('plugins.generic.plagiarism.tools.registerWebhooks.error'); + $this->getCommandInterface()->getOutput()->newLine(); + $this->getCommandInterface()->getOutput()->error($errorMessage); + + $responseDetails = $this->ithenticate->getLastResponseDetails(); + if (!$responseDetails) { + $this->getCommandInterface()->getOutput()->writeln( + 'No response details available (request may not have been made)' + ); + return; + } + + $this->getCommandInterface()->getOutput()->section('Full API Response Details'); + + // Display status code and reason + $this->getCommandInterface()->getOutput()->writeln( + sprintf( + 'Status Code: %d %s', + $responseDetails['status_code'], + $responseDetails['reason'] + ) + ); + + // Display response body + $this->getCommandInterface()->getOutput()->newLine(); + $this->getCommandInterface()->getOutput()->writeln('Response Body:'); + $bodyContent = $responseDetails['body']; + + // Try to pretty-print JSON if it's valid JSON + $decodedBody = json_decode($bodyContent, true); + if (json_last_error() === JSON_ERROR_NONE) { + $this->getCommandInterface()->getOutput()->writeln( + json_encode($decodedBody, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) + ); + } else { + $this->getCommandInterface()->getOutput()->writeln($bodyContent); + } + + // Display response headers + $this->getCommandInterface()->getOutput()->newLine(); + $this->getCommandInterface()->getOutput()->writeln('Response Headers:'); + foreach ($responseDetails['headers'] as $header => $values) { + $headerValues = is_array($values) ? implode(', ', $values) : $values; + $this->getCommandInterface()->getOutput()->writeln( + sprintf(' %s: %s', $header, $headerValues) + ); + } + } + /** * Delete the iThenticate webhook for given context */ - protected function delete(): bool + public function delete(): bool { - // If there is a already registered webhook for this context, need to delete it first - // before creating a new one as webhook URL when remains same, will return 409(HTTP_CONFLICT) - $existingWebhookId = $this->context->getData('ithenticateWebhookId'); - - if (!$existingWebhookId) { + $webhookId = $this->findWebhookIdForContext(); + + if (!$webhookId) { + if ($this->isIncludeApi()) { + $this->getCommandInterface()->getOutput()->info( + __('plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.nothingToDelete') + ); + } else { + $this->getCommandInterface()->getOutput()->info( + __('plugins.generic.plagiarism.tools.registerWebhooks.webhook.nothingToDelete') + ); + } return true; } - if (!$this->ithenticate->deleteWebhook($existingWebhookId)) { - // if the force flag not passed, will not continue to delete the webhook from database - // will only print the error and return - if (!in_array('--force', $this->getParameterList())) { + if (!$this->ithenticate->deleteWebhook($webhookId)) { + // Check if webhook simply doesn't exist at API (404 — already deleted) + $responseDetails = $this->ithenticate->getLastResponseDetails(); + $isNotFound = $responseDetails && ($responseDetails['status_code'] ?? 0) === 404; + + if ($isNotFound) { + // Webhook already gone from API — warn and continue to clean up DB + $this->getCommandInterface()->getOutput()->warning( + __( + 'plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.notFoundAtApi', + ['webhookId' => $webhookId] + ) + ); + } elseif (!$this->hasFlagSet('--force')) { + // Real API failure — error and abort (unless --force) $this->getCommandInterface()->getOutput()->error( __( 'plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.error', - ['webhookId' => $existingWebhookId, 'contextId' => $this->context->getId()] + [ + 'webhookId' => $webhookId, + 'contextId' => isset($this->context) ? $this->context->getId() : 'N/A' + ] ) ); + $this->displayApiResponseDetails("Deleting ithenticate webhook id : {$webhookId} failed via iThenticate API"); + return false; } } - $contextService = Services::get('context'); /** @var \APP\services\ContextService $contextService */ - - $this->context = $contextService->edit($this->context, [ - 'ithenticateWebhookSigningSecret' => null, - 'ithenticateWebhookId' => null - ], Application::get()->getRequest()); + // Clear DB only if the deleted webhook ID matches what's stored + if (isset($this->context) && $this->context->getData('ithenticateWebhookId')) { + $dbWebhookId = $this->context->getData('ithenticateWebhookId'); + + if ($dbWebhookId === $webhookId) { + $contextService = Services::get('context'); /** @var \APP\services\ContextService $contextService */ + $this->context = $contextService->edit($this->context, [ + 'ithenticateWebhookSigningSecret' => null, + 'ithenticateWebhookId' => null + ], Application::get()->getRequest()); + } else { + // Deleted webhook differs from DB record — preserve DB + $this->getCommandInterface()->getOutput()->info( + __( + 'plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.dbPreserved', + ['deletedId' => $webhookId, 'dbId' => $dbWebhookId] + ) + ); + } + } $this->getCommandInterface()->getOutput()->success( __( 'plugins.generic.plagiarism.tools.registerWebhooks.webhook.deleted.success', - ['webhookId' => $existingWebhookId, 'contextId' => $this->context->getId()] + [ + 'webhookId' => $webhookId, + 'contextId' => isset($this->context) ? $this->context->getId() : 'N/A' + ] ) ); @@ -431,13 +630,53 @@ public function usage(): void /** * Register a new iThenticate webhook for given context */ - protected function register(): void + public function register(): void { - if ($this->context->getData('ithenticateWebhookId') && $this->validate()) { - $this->getCommandInterface()->getOutput()->warning( - __('plugins.generic.plagiarism.tools.registerWebhooks.webhook.already.configured') - ); - return; + if ($this->isIncludeApi()) { + // Check BOTH DB and API for existing webhook + $webhookUrl = $this->plagiarismPlugin->getWebhookUrl($this->context); + $apiWebhookId = $this->ithenticate->findWebhookIdByUrl($webhookUrl); + $dbWebhookId = $this->context->getData('ithenticateWebhookId'); + + if ($dbWebhookId && $apiWebhookId) { + if ($dbWebhookId === $apiWebhookId) { + // Healthy — same webhook in both DB and API + $this->getCommandInterface()->getOutput()->warning( + __('plugins.generic.plagiarism.tools.registerWebhooks.webhook.already.configured') + ); + return; + } + + // Mismatch — DB points to different webhook than API URL match + $this->getCommandInterface()->getOutput()->warning( + __( + 'plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.dbApiMismatch', + ['dbId' => $dbWebhookId, 'apiId' => $apiWebhookId, 'url' => $webhookUrl] + ) + ); + return; + } + + if (!$dbWebhookId && $apiWebhookId) { + // Orphaned at API -- inform user + $this->getCommandInterface()->getOutput()->warning( + __( + 'plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.orphaned', + ['webhookId' => $apiWebhookId, 'url' => $webhookUrl] + ) + ); + return; + } + + // If DB has it but API doesn't, or neither has it -- proceed to register + } else { + // DB-only check (current behavior) + if ($this->context->getData('ithenticateWebhookId')) { + $this->getCommandInterface()->getOutput()->warning( + __('plugins.generic.plagiarism.tools.registerWebhooks.webhook.already.configured') + ); + return; + } } $this->update(); @@ -446,7 +685,7 @@ protected function register(): void /** * Update the iThenticate webhook for given context */ - protected function update(): void + public function update(): void { if (!$this->delete()) { $this->getCommandInterface()->getOutput()->error(__('plugins.generic.plagiarism.tools.registerWebhooks.error')); @@ -464,22 +703,27 @@ protected function update(): void return; } - $this->getCommandInterface()->getOutput()->error(__('plugins.generic.plagiarism.tools.registerWebhooks.error')); - } + // Display the detailed API response with reason of failure + $this->displayApiResponseDetails('Failed Registering new webhook'); + } /** * Validate the iThenticate webhook for given context */ - protected function validate(): bool + public function validate(): bool { // Re-fetch the context to ensure the latest data is loaded - $this->context = $this->getContext(); + if (isset($this->context)) { + $this->context = $this->getContext(); + } - if (!$this->context->getData('ithenticateWebhookId')) { + $webhookId = $this->findWebhookIdForContext(); + + if (!$webhookId) { $this->getCommandInterface()->getOutput()->error( __( 'plugins.generic.plagiarism.webhook.configuration.missing', - ['contextId' => $this->context->getId()] + ['contextId' => isset($this->context) ? $this->context->getId() : 'N/A'] ) ); return false; @@ -487,8 +731,8 @@ protected function validate(): bool $webhookResult = null; - $validity = $this->ithenticate->validateWebhook($this->context->getData('ithenticateWebhookId'), $webhookResult); - + $validity = $this->ithenticate->validateWebhook($webhookId, $webhookResult); + if ($webhookResult) { $webhookResult = json_decode($webhookResult, true); $collection = collect($webhookResult); @@ -510,14 +754,14 @@ protected function validate(): bool // Use HEAD for minimal bandwidth (checks existence/reachability without body) $response = Http::timeout(static::REACHABILITY_TIMEOUT)->head($url); - + // Fallback to GET if HEAD isn't supported by the server if (!$response->successful()) { $response = Http::timeout(static::REACHABILITY_TIMEOUT)->get($url); } array_push($values, $response->successful() ? 'YES' : 'NO'); - + } catch (\Illuminate\Http\Client\ConnectionException $e) { array_push($values, "FAILED - Message: {$e->getMessage()}"); } catch (\Exception $e) { @@ -535,6 +779,24 @@ protected function validate(): bool $table->render(); } + // If validation failed, display the full API response for debugging + if (!$validity) { + $this->displayApiResponseDetails("Failed validating webhook id : {$webhookId}"); + } + + // Inform user if the validated webhook ID differs from what's in DB + if ($this->isIncludeApi() && isset($this->context)) { + $dbWebhookId = $this->context->getData('ithenticateWebhookId'); + if ($dbWebhookId && $dbWebhookId !== $webhookId) { + $this->getCommandInterface()->getOutput()->warning( + __( + 'plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.validateDbMismatch', + ['validatedId' => $webhookId, 'dbId' => $dbWebhookId] + ) + ); + } + } + return $validity; } @@ -543,23 +805,105 @@ protected function validate(): bool */ public function list(): void { - $contextDao = Application::getContextDAO(); - $contexts = $contextDao->getAll(true); - - $rows = []; - while ($context = $contexts->next()) { /** @var Context $context */ - $rows[] = [ - $context->getId(), - $context->getPath(), - $context->getData('ithenticateWebhookId') ?? 'Not configured', - $context->getData('ithenticateWebhookId') ? 'Yes' : 'No' - ]; - } - - $this->getCommandInterface()->getOutput()->table( - ['ID', 'Path', 'Webhook ID', 'Configured'], - $rows - ); + if ($this->isIncludeApi()) { + $this->listApiWebhooks(); + } + + // DB-based listing (always runs when context is available or --include-api is not set) + if (!$this->isIncludeApi() || isset($this->context)) { + if ($this->isIncludeApi()) { + $this->getCommandInterface()->getOutput()->newLine(); + $this->getCommandInterface()->getOutput()->section('Database Webhook Status'); + } + + $contextDao = Application::getContextDAO(); + $contexts = $contextDao->getAll(true); + + $rows = []; + while ($context = $contexts->next()) { /** @var Context $context */ + $rows[] = [ + $context->getId(), + $context->getPath(), + $context->getData('ithenticateWebhookId') ?? 'Not configured', + $context->getData('ithenticateWebhookId') ? 'Yes' : 'No' + ]; + } + + $this->getCommandInterface()->getOutput()->table( + ['ID', 'Path', 'Webhook ID', 'Configured'], + $rows + ); + } + } + + /** + * List webhooks registered at iThenticate API for the current credentials + */ + protected function listApiWebhooks(): void + { + $output = $this->getCommandInterface()->getOutput(); + $output->section('API Webhooks (iThenticate)'); + + $webhooks = $this->ithenticate->listWebhooks(); + + if (empty($webhooks)) { + $output->info( + __('plugins.generic.plagiarism.tools.registerWebhooks.webhook.includeApi.list.empty') + ); + return; + } + + // Build context webhook URL for comparison (if context available) + $contextWebhookUrl = isset($this->context) + ? $this->plagiarismPlugin->getWebhookUrl($this->context) + : null; + $dbWebhookId = isset($this->context) + ? $this->context->getData('ithenticateWebhookId') + : null; + + $total = count($webhooks); + $index = 0; + + foreach ($webhooks as $webhook) { + $index++; + $webhookId = $webhook['id'] ?? 'N/A'; + $webhookUrl = $webhook['url'] ?? 'N/A'; + $eventTypes = isset($webhook['event_types']) + ? implode(', ', $webhook['event_types']) + : 'N/A'; + $createdTime = $webhook['created_time'] ?? 'N/A'; + + // Determine match status + $matchStatus = '-'; + $urlMatch = $contextWebhookUrl && $webhookUrl === $contextWebhookUrl; + $dbMatch = $dbWebhookId && $webhookId === $dbWebhookId; + + if ($urlMatch && $dbMatch) { + $matchStatus = 'YES (URL + DB)'; + } elseif ($urlMatch) { + $matchStatus = 'YES (URL match, not in DB)'; + } elseif ($dbMatch) { + $matchStatus = 'YES (DB match, URL differs)'; + } + + $output->writeln("Webhook {$index} of {$total}"); + + $table = new \Symfony\Component\Console\Helper\Table($output); + $table->setHeaders(['Property', 'Value']); + $table->setRows([ + ['Webhook ID', $webhookId], + ['URL', $webhookUrl], + ['Events', $eventTypes], + ['Created', $createdTime], + ['Matches Context', $matchStatus], + ]); + $table->setColumnMaxWidth(1, 80); + $table->render(); + + if ($index < $total) { + $output->newLine(); + } + } } }