diff --git a/.claude/commands/test.md b/.claude/commands/test.md index 621add25..50749714 100644 --- a/.claude/commands/test.md +++ b/.claude/commands/test.md @@ -5,7 +5,7 @@ category: Testing tags: [testing, softwarecatalogus, newman, playwright, persona] --- -Base directory for this skill: /home/rubenlinde/nextcloud-docker-dev/workspace/server/apps-extra/softwarecatalog +Base directory for this skill: /home/rubenlinde/nextcloud-docker-dev/workspace/server/apps-extra/stackiq # Test Softwarecatalogus — Orchestrator @@ -57,33 +57,33 @@ When running API tests, use Newman CLI: which newman || npm install -g newman newman-reporter-htmlextra # Run setup first (creates test data) -newman run softwarecatalog/postman/softwarecatalogus-tests.json \ - -e softwarecatalog/postman/environment-local.json \ +newman run stackiq/postman/softwarecatalogus-tests.json \ + -e stackiq/postman/environment-local.json \ --folder "00 - Setup" --reporters cli 2>&1 | tail -20 # Run all test folders -newman run softwarecatalog/postman/softwarecatalogus-tests.json \ - -e softwarecatalog/postman/environment-local.json \ +newman run stackiq/postman/softwarecatalogus-tests.json \ + -e stackiq/postman/environment-local.json \ --reporters cli,htmlextra \ - --reporter-htmlextra-export softwarecatalog/test-results/api/report.html 2>&1 + --reporter-htmlextra-export stackiq/test-results/api/report.html 2>&1 # Run a specific folder -newman run softwarecatalog/postman/softwarecatalogus-tests.json \ - -e softwarecatalog/postman/environment-local.json \ +newman run stackiq/postman/softwarecatalogus-tests.json \ + -e stackiq/postman/environment-local.json \ --folder "{folder-name}" --reporters cli 2>&1 ``` **For custom environments**, pass variables: ```bash -newman run softwarecatalog/postman/softwarecatalogus-tests.json \ - -e softwarecatalog/postman/environment-local.json \ +newman run stackiq/postman/softwarecatalogus-tests.json \ + -e stackiq/postman/environment-local.json \ --env-var "base_url={BACKEND}" \ --env-var "admin_user={ADMIN_USER}" \ --env-var "admin_pass={ADMIN_PASS}" \ --reporters cli 2>&1 ``` -Write API results to `softwarecatalog/test-results/api/results.md`. +Write API results to `stackiq/test-results/api/results.md`. --- @@ -200,7 +200,7 @@ After EVERY page navigation, check network performance: - Search queries with >5 active filters ### Acceptance Criteria -Before testing each issue, read its detailed acceptance criteria in `softwarecatalog/issues.md`. Each issue has specific, testable acceptance criteria with checkboxes. Use these to determine status: +Before testing each issue, read its detailed acceptance criteria in `stackiq/issues.md`. Each issue has specific, testable acceptance criteria with checkboxes. Use these to determine status: - **PASS** = ALL acceptance criteria are met - **PARTIAL** = Some criteria met, some not - **FAIL** = Key criteria not met or feature is broken @@ -217,7 +217,7 @@ CMS pages (privacy, terms, FAQ, disclaimer) are managed in the **OpenCatalogi** ### RBAC Reference The authoritative RBAC rules are defined in the register JSON configuration: -- **File**: `softwarecatalog/lib/Settings/softwarecatalogus_register.json` +- **File**: `stackiq/lib/Settings/softwarecatalogus_register.json` - Each schema has an `"authorization"` block with `create`, `read`, `update`, `delete` rules - Rules can be simple group names (e.g., `"public"`, `"gebruik-beheerder"`) or conditional: `{ "group": "aanbod-beheerder", "match": { "_organisation": "$organisation" } }` (only own org's data) @@ -261,7 +261,7 @@ After all testing is complete, agents **MUST** clean up any objects they created ### Rules - **READ ONLY on GitHub issues** — NEVER update, close, or comment on issues -- Write test results ONLY to local files in `softwarecatalog/test-results/` +- Write test results ONLY to local files in `stackiq/test-results/` - Take screenshots as evidence where applicable - **ALWAYS clean up test data** created during wizard walkthroughs (see Test Data Cleanup above) @@ -289,10 +289,10 @@ Run the setup script to create test organizations, contact persons, user account ```bash # Local (default): -bash softwarecatalog/test-setup.sh +bash stackiq/test-setup.sh # Custom environment: -BACKEND_URL="{BACKEND}" ADMIN_USER="{ADMIN_USER}" ADMIN_PASS="{ADMIN_PASS}" bash softwarecatalog/test-setup.sh +BACKEND_URL="{BACKEND}" ADMIN_USER="{ADMIN_USER}" ADMIN_PASS="{ADMIN_PASS}" bash stackiq/test-setup.sh ``` This script creates: @@ -334,7 +334,7 @@ Run the Postman/Newman API test suite. This covers all `[API]`-tagged acceptance which newman || npm install -g newman newman-reporter-htmlextra ``` -**After Newman completes**, parse the output and write results to `softwarecatalog/test-results/api/results.md`: +**After Newman completes**, parse the output and write results to `stackiq/test-results/api/results.md`: - Total requests, assertions, passes, failures - Per-folder pass/fail counts - Failed test names with issue references (tests are named `#NNN AC: description`) @@ -366,7 +366,7 @@ Note: All 7 browsers are used. The bezoeker uses browser-6 (does not need headed You are a testing agent for the GEMMA Softwarecatalogus. Read and follow the instructions in the skill file at: -softwarecatalog/.claude/skills/test-{persona}.md +stackiq/.claude/skills/test-{persona}.md This file contains your persona details, login credentials, test scope, and the list of issues to test. @@ -418,7 +418,7 @@ Your persona is linked to a proper organization (not Default Organisation): Organization-specific features (wizards, filters, dashboards) should work for your persona's org type. ### RBAC Reference -The authoritative RBAC rules are in `softwarecatalog/lib/Settings/softwarecatalogus_register.json`. +The authoritative RBAC rules are in `stackiq/lib/Settings/softwarecatalogus_register.json`. Each schema has an `"authorization"` block. Key rules: - **contactpersoon**: NOT public, but leverancier contact persons ARE expected to be publicly visible via publications. Only gemeente contact persons should be hidden. - **module** (applicatie): Public can read only where `geregistreerdDoor: Leverancier`. aanbod-beheerder sees only own org. @@ -523,11 +523,11 @@ After completing all tests, you MUST clean up any objects you created during wiz **Why this matters:** Without cleanup, wizard re-runs create duplicate entries that cause false FAIL results for count-based issues (#300, #307). ### Acceptance Criteria -Before testing each issue, read its acceptance criteria from softwarecatalog/issues.md. +Before testing each issue, read its acceptance criteria from stackiq/issues.md. The file contains detailed checkboxes for each issue. Use these to determine PASS/FAIL/PARTIAL/CANNOT_TEST. ### Output Format -Write your results to: softwarecatalog/test-results/{persona}/results-authenticated.md +Write your results to: stackiq/test-results/{persona}/results-authenticated.md Use this format: - Header with persona name, date, environment, login used @@ -557,20 +557,20 @@ If any agent fails (crashes, doesn't write results), log the failure and continu After all tests complete (or in `summary-only` mode), read all result files and generate a summary. **Read these files** (if they exist): -- `softwarecatalog/test-results/api/results.md` (API test results) -- `softwarecatalog/test-results/leverancier/results-authenticated.md` -- `softwarecatalog/test-results/gemeente/results-authenticated.md` -- `softwarecatalog/test-results/security-officer/results-authenticated.md` -- `softwarecatalog/test-results/functioneel-beheerder/results-authenticated.md` -- `softwarecatalog/test-results/samenwerking/results-authenticated.md` -- `softwarecatalog/test-results/architectuur-expert/results-authenticated.md` -- `softwarecatalog/test-results/bezoeker/results-public.md` +- `stackiq/test-results/api/results.md` (API test results) +- `stackiq/test-results/leverancier/results-authenticated.md` +- `stackiq/test-results/gemeente/results-authenticated.md` +- `stackiq/test-results/security-officer/results-authenticated.md` +- `stackiq/test-results/functioneel-beheerder/results-authenticated.md` +- `stackiq/test-results/samenwerking/results-authenticated.md` +- `stackiq/test-results/architectuur-expert/results-authenticated.md` +- `stackiq/test-results/bezoeker/results-public.md` For each file, extract: - Issue number, title, status (PASS/PARTIAL/FAIL/CANNOT_TEST), severity - Agent/method that tested it (API or persona name) -**Write the summary to**: `softwarecatalog/test-results/README.md` +**Write the summary to**: `stackiq/test-results/README.md` ### Summary Report Format @@ -707,11 +707,11 @@ After writing the summary, display a concise overview to the user: - Total issues tested - PASS/FAIL/PARTIAL/CANNOT_TEST counts - Top 3 critical findings -- Link to the full report: `softwarecatalog/test-results/README.md` +- Link to the full report: `stackiq/test-results/README.md` ### Step 6: Backlog Suggestions -After presenting the report, review the test findings for **suggestions and improvements** that are NOT existing GitHub issues but could be valuable. Present these to the user and ask if they should be added to the backlog at `softwarecatalog/website/docs/backlog.md`. +After presenting the report, review the test findings for **suggestions and improvements** that are NOT existing GitHub issues but could be valuable. Present these to the user and ask if they should be added to the backlog at `stackiq/website/docs/backlog.md`. Examples of backlog-worthy suggestions: - UX improvements noticed during testing (e.g., inconsistent naming, confusing navigation) @@ -730,7 +730,7 @@ When the argument starts with `issues`, this workflow processes open IGS issues ### Step 7: Build Issue List -Read `softwarecatalog/aanvullende-informatie.md` to get the full list of open issues with their categories. +Read `stackiq/aanvullende-informatie.md` to get the full list of open issues with their categories. **Filter based on argument:** - `issues` → all 72 open issues @@ -756,10 +756,10 @@ Your task is to process the following open issues and prepare a GitHub reply com For EACH issue number in your list: ### 1. Read the issue -Read `softwarecatalog/issues/{number}.md` for the full description, comments, and images. +Read `stackiq/issues/{number}.md` for the full description, comments, and images. ### 2. Determine the category -Look up the issue in `softwarecatalog/aanvullende-informatie.md` to find its category (Bug, Datakwaliteit, Tekstueel, Wens, Nog te bepalen). +Look up the issue in `stackiq/aanvullende-informatie.md` to find its category (Bug, Datakwaliteit, Tekstueel, Wens, Nog te bepalen). ### 3. Investigate based on category @@ -767,11 +767,11 @@ Look up the issue in `softwarecatalog/aanvullende-informatie.md` to find its cat 1. Navigate to the relevant page in the browser (Frontend: {FRONTEND}, Backend: {BACKEND}) 2. Try to reproduce the problem described in the issue 3. Take screenshots showing the current state (whether fixed or still broken) -4. If it involves RBAC, check `softwarecatalog/lib/Settings/softwarecatalogus_register.json` +4. If it involves RBAC, check `stackiq/lib/Settings/softwarecatalogus_register.json` 5. Use the appropriate template from aanvullende-informatie.md (Template A if fixed, Template B if still broken) **Datakwaliteit issues:** -1. Read the relevant CSV file(s) from `softwarecatalog/data/` +1. Read the relevant CSV file(s) from `stackiq/data/` 2. Search for the specific data causing the issue (orphaned references, missing fields, etc.) 3. Count affected records and provide examples 4. Use Template C from aanvullende-informatie.md @@ -783,7 +783,7 @@ Look up the issue in `softwarecatalog/aanvullende-informatie.md` to find its cat 4. Use Template D from aanvullende-informatie.md **Wens issues:** -1. Read `softwarecatalog/issues.md` to confirm this is outside the original PvE scope +1. Read `stackiq/issues.md` to confirm this is outside the original PvE scope 2. Describe current behavior 3. Use Template E from aanvullende-informatie.md @@ -793,11 +793,11 @@ Look up the issue in `softwarecatalog/aanvullende-informatie.md` to find its cat 3. Follow that category's procedure ### 4. Write the reply -Save the prepared reply as: `softwarecatalog/reacties/{number}.md` +Save the prepared reply as: `stackiq/reacties/{number}.md` Include the issue title as an H1 header, the category, and the reply content using the appropriate template. ### 5. Save screenshots -Save any screenshots to: `softwarecatalog/reacties/screenshots/{number}-{description}.png` +Save any screenshots to: `stackiq/reacties/screenshots/{number}-{description}.png` ## Browser Assignment Use browser-{browser_num} for ALL browser operations (mcp__browser-{browser_num}__* tools). @@ -808,16 +808,16 @@ For issues requiring authenticated access, log in as admin ({ADMIN_USER}/{ADMIN_ For public-facing issues, test without logging in. ## Data Files -CSV import data is in `softwarecatalog/data/`: +CSV import data is in `stackiq/data/`: - module.csv (applicaties), koppeling.csv, organisatie.csv, contactpersoon.csv - compliancy.csv, gebruik.csv, gebruik_2.csv, gebruik_3.csv, moduleversie.csv -GEMMA AMEF model: `softwarecatalog/data/GEMMA release.xml` +GEMMA AMEF model: `stackiq/data/GEMMA release.xml` ## Rules — CRITICAL - NEVER update, close, or comment on GitHub issues — this is PREPARATION ONLY - NEVER post anything to GitHub — all output is LOCAL files for human review -- Write replies ONLY to local files in softwarecatalog/reacties/ +- Write replies ONLY to local files in stackiq/reacties/ - Take screenshots as evidence - Do NOT use gh CLI to interact with issues in any way ``` @@ -827,14 +827,14 @@ GEMMA AMEF model: `softwarecatalog/data/GEMMA release.xml` Wait for all issue agents to complete. Create the output directory if needed: ```bash -mkdir -p softwarecatalog/reacties/screenshots +mkdir -p stackiq/reacties/screenshots ``` ### Step 10: Generate Issues Summary -After all agents complete, read all files in `softwarecatalog/reacties/` and generate a summary. +After all agents complete, read all files in `stackiq/reacties/` and generate a summary. -**Write to**: `softwarecatalog/reacties/README.md` +**Write to**: `stackiq/reacties/README.md` ```markdown # IGS Issues — Voorbereide Reacties diff --git a/.claude/commands/update.md b/.claude/commands/update.md index 4794fd8b..388d4de5 100644 --- a/.claude/commands/update.md +++ b/.claude/commands/update.md @@ -10,7 +10,7 @@ tags: [testing, softwarecatalogus, sync, issues, acceptance-criteria] Synchronize GitHub issues from `VNG-Realisatie/Softwarecatalogus` into local files, auto-generate acceptance criteria, and update both Postman tests and browser test agent skill files. **Target repo**: `VNG-Realisatie/Softwarecatalogus` -**Local directory**: `softwarecatalog/` +**Local directory**: `stackiq/` **Input**: Optional argument after `/swc:update`: - No argument → incremental sync (changes since last run) @@ -24,7 +24,7 @@ Synchronize GitHub issues from `VNG-Realisatie/Softwarecatalogus` into local fil ### Step 1: Read last-update timestamp -Read `softwarecatalog/.last-update`. This file contains a single ISO 8601 timestamp (e.g., `2026-03-04T12:00:00Z`). +Read `stackiq/.last-update`. This file contains a single ISO 8601 timestamp (e.g., `2026-03-04T12:00:00Z`). - If the file **exists**: use its content as `SINCE_TIMESTAMP` - If the file **does not exist**: first run. Set `SINCE_TIMESTAMP` to empty (fetch ALL open issues) @@ -60,7 +60,7 @@ Skip the list query. Fetch each specified issue individually in Step 4. For each issue in the result set: -- **NEW**: No file exists at `softwarecatalog/issues/{number}.md` +- **NEW**: No file exists at `stackiq/issues/{number}.md` - **UPDATED**: File exists AND GitHub `updatedAt` is after `SINCE_TIMESTAMP` - **CLOSED**: Issue `state` is `"closed"` - **UNCHANGED**: File exists AND not updated since last sync → skip @@ -83,7 +83,7 @@ gh issue view {NUMBER} --repo VNG-Realisatie/Softwarecatalogus \ ### Step 5: Write individual issue files -Write/overwrite `softwarecatalog/issues/{number}.md` using the **established format**: +Write/overwrite `stackiq/issues/{number}.md` using the **established format**: ```markdown # #{number} — {title} @@ -112,7 +112,7 @@ Write/overwrite `softwarecatalog/issues/{number}.md` using the **established for ... ``` -**Formatting rules** (match existing files in `softwarecatalog/issues/`): +**Formatting rules** (match existing files in `stackiq/issues/`): - Title uses `# #{number} — {title}` (em-dash `—`, not hyphen) - Status is UPPERCASE: `OPEN` or `CLOSED` - Preserve HTML image tags from GitHub as-is (don't convert to markdown) @@ -124,7 +124,7 @@ Write/overwrite `softwarecatalog/issues/{number}.md` using the **established for ### Step 6: Read and parse current issues.md -Read `softwarecatalog/issues.md`. Understand its structure: +Read `stackiq/issues.md`. Understand its structure: - **Header** (first ~45 lines): date, summary counts, test type legend, recently closed list, new issues list - **IGS Issues section**: individual `### #{number}: {title}` blocks with acceptance criteria - **Other Issues section**: table of non-testable issues @@ -230,7 +230,7 @@ For issues that changed to CLOSED: ### Step 12: Update Postman collection for new [API] criteria -Read `softwarecatalog/postman/softwarecatalogus-tests.json` (Postman v2.1 format). +Read `stackiq/postman/softwarecatalogus-tests.json` (Postman v2.1 format). For each new issue with [API]-tagged criteria, determine the target folder: @@ -304,10 +304,10 @@ For each [API] criterion, create a Postman request item: ```bash python3 -c " import json -with open('softwarecatalog/postman/softwarecatalogus-tests.json', 'r') as f: +with open('stackiq/postman/softwarecatalogus-tests.json', 'r') as f: collection = json.load(f) # ... add new items to the appropriate folder ... -with open('softwarecatalog/postman/softwarecatalogus-tests.json', 'w') as f: +with open('stackiq/postman/softwarecatalogus-tests.json', 'w') as f: json.dump(collection, f, indent='\t', ensure_ascii=False) " ``` @@ -320,13 +320,13 @@ Determine which persona(s) should test each new issue: | Label / content | Primary persona | Skill file | |----------------|----------------|------------| -| "Aanbod", vendor features | leverancier | `softwarecatalog/.claude/skills/test-leverancier.md` | -| "Gebruik" (municipality) | gemeente | `softwarecatalog/.claude/skills/test-gemeente.md` | -| "Gebruik" (collaboration) | samenwerking | `softwarecatalog/.claude/skills/test-samenwerking.md` | -| "Zoeken" (unauthenticated) | bezoeker | `softwarecatalog/.claude/skills/test-bezoeker.md` | -| "Referentiearchitectuur" | architectuur-expert | `softwarecatalog/.claude/skills/test-architectuur-expert.md` | -| Security, privacy, RBAC | security-officer | `softwarecatalog/.claude/skills/test-security-officer.md` | -| Admin, CMS, config | functioneel-beheerder | `softwarecatalog/.claude/skills/test-functioneel-beheerder.md` | +| "Aanbod", vendor features | leverancier | `stackiq/.claude/skills/test-leverancier.md` | +| "Gebruik" (municipality) | gemeente | `stackiq/.claude/skills/test-gemeente.md` | +| "Gebruik" (collaboration) | samenwerking | `stackiq/.claude/skills/test-samenwerking.md` | +| "Zoeken" (unauthenticated) | bezoeker | `stackiq/.claude/skills/test-bezoeker.md` | +| "Referentiearchitectuur" | architectuur-expert | `stackiq/.claude/skills/test-architectuur-expert.md` | +| Security, privacy, RBAC | security-officer | `stackiq/.claude/skills/test-security-officer.md` | +| Admin, CMS, config | functioneel-beheerder | `stackiq/.claude/skills/test-functioneel-beheerder.md` | For each persona skill file, find the issues table (format: `| Issue | Title | ... |`) and add the new issue row in numerical order: ``` @@ -339,7 +339,7 @@ Also add brief testing instructions for the new issue in the "Detailed Testing I ### Step 14: Update aanvullende-informatie.md -Read `softwarecatalog/aanvullende-informatie.md`. Update: +Read `stackiq/aanvullende-informatie.md`. Update: - The total count in the header - Add new issues to the appropriate category section - Note any new functional areas not previously covered @@ -350,9 +350,9 @@ Read `softwarecatalog/aanvullende-informatie.md`. Update: ### Step 15: Write timestamp -Write the current UTC time as ISO 8601 to `softwarecatalog/.last-update`: +Write the current UTC time as ISO 8601 to `stackiq/.last-update`: ```bash -date -u +"%Y-%m-%dT%H:%M:%SZ" > softwarecatalog/.last-update +date -u +"%Y-%m-%dT%H:%M:%SZ" > stackiq/.last-update ``` ### Step 16: Present summary @@ -385,12 +385,12 @@ Output a structured summary to the user: {list of closed issue numbers and titles} ### Files Modified -- softwarecatalog/issues.md -- softwarecatalog/issues/{numbers}.md -- softwarecatalog/postman/softwarecatalogus-tests.json (if API tests added) -- softwarecatalog/.claude/skills/test-{persona}.md (list which ones) -- softwarecatalog/aanvullende-informatie.md -- softwarecatalog/.last-update +- stackiq/issues.md +- stackiq/issues/{numbers}.md +- stackiq/postman/softwarecatalogus-tests.json (if API tests added) +- stackiq/.claude/skills/test-{persona}.md (list which ones) +- stackiq/aanvullende-informatie.md +- stackiq/.last-update ``` ### Step 17: Offer test execution @@ -410,8 +410,8 @@ If the user chooses to test: **API tests**: Run Newman for only the affected folders: ```bash -newman run softwarecatalog/postman/softwarecatalogus-tests.json \ - -e softwarecatalog/postman/environment-local.json \ +newman run stackiq/postman/softwarecatalogus-tests.json \ + -e stackiq/postman/environment-local.json \ --folder "{affected-folder-name}" \ --reporters cli 2>&1 ``` @@ -420,7 +420,7 @@ Repeat for each folder that received new tests. **Browser tests**: Launch the affected persona agents using the same sub-agent pattern from `/swc:test`: - For each affected persona, launch a Task agent with the sub-agent prompt template from `/swc:test` Step 2 - BUT limit testing to only the new/updated issues (include a list of specific issue numbers in the prompt) -- Write results to `softwarecatalog/test-results/{persona}/results-authenticated.md` +- Write results to `stackiq/test-results/{persona}/results-authenticated.md` **Both**: Run API first, then browser. @@ -430,10 +430,10 @@ After testing completes, if any tests FAIL, ask the user: | Option | Label | Description | |--------|-------|-------------| -| 1 | **Yes, fix them** | I'll investigate the failures and implement fixes in the softwarecatalog app code | +| 1 | **Yes, fix them** | I'll investigate the failures and implement fixes in the stackiq app code | | 2 | **No, just report** | Save the test results for later review | -If the user wants fixes: read the test results, identify the root causes, and implement code fixes in the `softwarecatalog/` app. After fixing, re-run the affected tests to verify. +If the user wants fixes: read the test results, identify the root causes, and implement code fixes in the `stackiq/` app. After fixing, re-run the affected tests to verify. --- @@ -444,10 +444,10 @@ If the user wants fixes: read the test results, identify the root causes, and im - **NEVER** post comments, update labels, change state, or modify GitHub issues in any way - **ONLY** use `gh issue list` (to discover) and `gh issue view` (to read) — nothing else - **NEVER** push changes to any remote repository -- All output goes to LOCAL files in `softwarecatalog/` only +- All output goes to LOCAL files in `stackiq/` only ### Other rules -- All file writes go to `softwarecatalog/` only — NEVER write to `Softwarecatalogus/` +- All file writes go to `stackiq/` only — NEVER write to `Softwarecatalogus/` - Preserve existing acceptance criteria checkbox states (`[x]` and `[ ]`) - Use `python3` for Postman JSON manipulation (not manual text editing) - When in doubt about tag classification, default to `[HYBRID]` diff --git a/.claude/openspec/architecture/adr-022-apps-consume-or-abstractions.md b/.claude/openspec/architecture/adr-022-apps-consume-or-abstractions.md index 401aba39..c3e01c05 100644 --- a/.claude/openspec/architecture/adr-022-apps-consume-or-abstractions.md +++ b/.claude/openspec/architecture/adr-022-apps-consume-or-abstractions.md @@ -11,7 +11,7 @@ duplicate-ADR pattern this ADR was written to prevent). ## Context -Conduction maintains ~13 Nextcloud apps (decidesk, docudesk, pipelinq, procest, opencatalogi, openconnector, launchpad, larpingapp, shillinq/budgetq, zaakafhandelapp, nldesign, softwarecatalog, and the in-flight idea apps). Each app needs features that overlap heavily: objects with schemas, role-based access, audit trails, archival/retention policies, mapping/transformation, relation management, sidebar tabs with notes/tasks/files, dashboard widgets, integrations with NC-native and external services. +Conduction maintains ~13 Nextcloud apps (decidesk, docudesk, pipelinq, procest, opencatalogi, openconnector, launchpad, larpingapp, shillinq/budgetq, zaakafhandelapp, nldesign, stackiq, and the in-flight idea apps). Each app needs features that overlap heavily: objects with schemas, role-based access, audit trails, archival/retention policies, mapping/transformation, relation management, sidebar tabs with notes/tasks/files, dashboard widgets, integrations with NC-native and external services. OpenRegister has grown into the **foundation** that provides these as shared abstractions: registers, schemas, objects, RBAC, audit-trail-immutable, archival-destruction-workflow, mappings, relations, object-interactions, and — with ADR-019 — a pluggable integration registry. diff --git a/.claude/openspec/architecture/adr-024-app-manifest.md b/.claude/openspec/architecture/adr-024-app-manifest.md index fe368f8d..6854ce3d 100644 --- a/.claude/openspec/architecture/adr-024-app-manifest.md +++ b/.claude/openspec/architecture/adr-024-app-manifest.md @@ -91,7 +91,7 @@ Specifically: reflected in `src/manifest.json` is treated as drift. (Pairs with ADR-029 route-reachability gate.) - Migration order recommendation (cheapest → highest-value): - `launchpad` → `larpingapp` / `softwarecatalog` → `openregister` → + `launchpad` → `larpingapp` / `stackiq` → `openregister` → remaining apps. Decidesk is already Tier 4 and serves as the reference. - App-manifest extensions (e.g. `theme: { primary, accent, logoUrl }`, diff --git a/.claude/skills/test-architectuur-expert.md b/.claude/skills/test-architectuur-expert.md index 17e87242..7e3b771e 100644 --- a/.claude/skills/test-architectuur-expert.md +++ b/.claude/skills/test-architectuur-expert.md @@ -25,7 +25,7 @@ Sarah validates GEMMA compliance, reviews architecture decisions, and monitors c ## Organization & Permissions Context -Sarah's account is in the Default Organisation (expected for VNG roles). The org permission system requires the internal Nextcloud org UUID to match a register object. If org fetch fails (404 in console), edit/delete buttons will be disabled — this is expected for VNG-raadpleger roles that primarily read/view rather than edit. Run `bash softwarecatalog/test-setup.sh` if org assignments are broken. +Sarah's account is in the Default Organisation (expected for VNG roles). The org permission system requires the internal Nextcloud org UUID to match a register object. If org fetch fails (404 in console), edit/delete buttons will be disabled — this is expected for VNG-raadpleger roles that primarily read/view rather than edit. Run `bash stackiq/test-setup.sh` if org assignments are broken. ## Test Scope diff --git a/.claude/skills/test-bezoeker.md b/.claude/skills/test-bezoeker.md index 48207ff7..714016b3 100644 --- a/.claude/skills/test-bezoeker.md +++ b/.claude/skills/test-bezoeker.md @@ -144,7 +144,7 @@ As an unauthenticated visitor, you should only see data that has `"public"` read ## Output Format -Write results to: `softwarecatalog/test-results/bezoeker/results-public.md` +Write results to: `stackiq/test-results/bezoeker/results-public.md` Use this format: - Header with persona name, date, environment diff --git a/.claude/skills/test-functioneel-beheerder.md b/.claude/skills/test-functioneel-beheerder.md index 6e393a1b..3e3d66c9 100644 --- a/.claude/skills/test-functioneel-beheerder.md +++ b/.claude/skills/test-functioneel-beheerder.md @@ -30,7 +30,7 @@ Peter's account (`peter.vandijk@test.nl`) is in the Default Organisation. **Impo - **For frontend beheer testing**: Log in as `peter.vandijk@test.nl` (NOT `admin`). Peter has full admin group membership and a proper org assignment. - **For Nextcloud backend testing** (OpenCatalogi admin, OpenRegister config): Use `admin:admin` via the backend URL — these features don't depend on the org permission system. -- If you see "org fetch error" or disabled edit/delete buttons, the active org UUID doesn't have a matching register object. Run `bash softwarecatalog/test-setup.sh` to fix org assignments. +- If you see "org fetch error" or disabled edit/delete buttons, the active org UUID doesn't have a matching register object. Run `bash stackiq/test-setup.sh` to fix org assignments. ## Test Scope diff --git a/.claude/skills/test-gemeente.md b/.claude/skills/test-gemeente.md index 6c2facf0..c3ddf8ed 100644 --- a/.claude/skills/test-gemeente.md +++ b/.claude/skills/test-gemeente.md @@ -30,7 +30,7 @@ Maria's active organization is **Test Gemeente**. The internal Nextcloud org UUI - **Beheer tables** show objects based on RBAC rules — gebruik-beheerder can see ALL objects (not just own org) for most schemas - **Edit/Delete buttons** require the org data fetch to succeed — if you see disabled actions or missing buttons, check for org fetch 404 errors in the console - **Do NOT test beheer as admin** — admin's "Default Organisation" has no register object, so org fetch always fails and permissions are broken -- The test setup script (`bash softwarecatalog/test-setup.sh`) creates test objects as maria.vanderberg so they get the correct org assignment +- The test setup script (`bash stackiq/test-setup.sh`) creates test objects as maria.vanderberg so they get the correct org assignment - If beheer tables are empty or missing expected test objects, run the test setup script ## Test Scope diff --git a/.claude/skills/test-leverancier.md b/.claude/skills/test-leverancier.md index e529d747..5e8e09e1 100644 --- a/.claude/skills/test-leverancier.md +++ b/.claude/skills/test-leverancier.md @@ -30,7 +30,7 @@ Jan's active organization is **Test Leverancier BV**. The internal Nextcloud org - **Beheer tables** only show objects owned by Jan's org (RBAC scoping by `@self.organisation`) - **Edit/Delete buttons** require the org data fetch to succeed — if you see disabled actions or missing buttons, check for org fetch 404 errors in the console - **Do NOT test beheer as admin** — admin's "Default Organisation" has no register object, so org fetch always fails and permissions are broken -- The test setup script (`bash softwarecatalog/test-setup.sh`) creates test objects as jan.pietersen so they get the correct org assignment +- The test setup script (`bash stackiq/test-setup.sh`) creates test objects as jan.pietersen so they get the correct org assignment - If beheer tables are empty, run the test setup script to create/verify test objects ## Test Scope diff --git a/.claude/skills/test-samenwerking.md b/.claude/skills/test-samenwerking.md index 3b33b920..d658b550 100644 --- a/.claude/skills/test-samenwerking.md +++ b/.claude/skills/test-samenwerking.md @@ -25,7 +25,7 @@ Linda represents a collaboration that acts as BOTH a supplier (offering shared s ## Organization & Permissions Context -Linda's active organization is **Test Samenwerking**. The org permission system requires the internal Nextcloud org UUID to match a register object in `voorzieningen/organisatie`. If org fetch fails (404 in console), edit/delete buttons will be disabled. Do NOT test beheer features as `admin` — use the test persona accounts. Run `bash softwarecatalog/test-setup.sh` if org assignments are broken. +Linda's active organization is **Test Samenwerking**. The org permission system requires the internal Nextcloud org UUID to match a register object in `voorzieningen/organisatie`. If org fetch fails (404 in console), edit/delete buttons will be disabled. Do NOT test beheer features as `admin` — use the test persona accounts. Run `bash stackiq/test-setup.sh` if org assignments are broken. ## Test Scope diff --git a/.claude/skills/test-security-officer.md b/.claude/skills/test-security-officer.md index 49ef76ca..326026f6 100644 --- a/.claude/skills/test-security-officer.md +++ b/.claude/skills/test-security-officer.md @@ -25,7 +25,7 @@ Mark monitors security requirements, validates privacy implementations, and ensu ## Organization & Permissions Context -Mark's active organization is **Test Gemeente** (same as Maria). The org permission system requires the internal Nextcloud org UUID to match a register object in `voorzieningen/organisatie`. If org fetch fails (404 in console), edit/delete buttons will be disabled. Do NOT test beheer features as `admin` — use the test persona accounts. Run `bash softwarecatalog/test-setup.sh` if org assignments are broken. +Mark's active organization is **Test Gemeente** (same as Maria). The org permission system requires the internal Nextcloud org UUID to match a register object in `voorzieningen/organisatie`. If org fetch fails (404 in console), edit/delete buttons will be disabled. Do NOT test beheer features as `admin` — use the test persona accounts. Run `bash stackiq/test-setup.sh` if org assignments are broken. ## Test Scope @@ -51,7 +51,7 @@ Mark's active organization is **Test Gemeente** (same as Maria). The org permiss - [ ] Direct URL access to restricted resources returns 403/404 #### RBAC Reference -The authoritative RBAC rules are in `softwarecatalog/lib/Settings/softwarecatalogus_register.json`. Each schema has an `authorization` block. Key rules: +The authoritative RBAC rules are in `stackiq/lib/Settings/softwarecatalogus_register.json`. Each schema has an `authorization` block. Key rules: - **contactpersoon**: NOT public read. Leverancier contacts visible via publications only. Gemeente/samenwerking contacts should be hidden. - **module** (applicatie): Public can read only where `geregistreerdDoor: Leverancier`. Aanbod-beheerder sees own org only. - **koppeling**: NOT public. Gebruik-beheerder sees all; aanbod-beheerder sees own org only. diff --git a/.cursor/rules/global.mdc b/.cursor/rules/global.mdc index a5c42cf9..0ebcecec 100644 --- a/.cursor/rules/global.mdc +++ b/.cursor/rules/global.mdc @@ -23,14 +23,14 @@ The ArchiMate import process follows these steps: #### 2. Testing Import API Endpoint ```bash # Test import from within Docker container (REQUIRED) -docker exec -it nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" \ +docker exec -it nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import" \ -u admin:admin \ -F "archiMateFile=@/var/www/html/data/admin/files/GEMMA_smaller.xml" \ -F "updateExisting=true" \ -F "preserveIds=true" # Test with different options -docker exec -it nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" \ +docker exec -it nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import" \ -u admin:admin \ -F "archiMateFile=@/var/www/html/data/admin/files/GEMMA_release.xml" \ -F "updateExisting=false" \ @@ -40,13 +40,13 @@ docker exec -it nextcloud curl -X POST "http://localhost/index.php/apps/software #### 3. Monitoring Import Progress ```bash # Check import status -docker exec -u 33 nextcloud php occ config:app:get softwarecatalog archimate_import_status +docker exec -u 33 nextcloud php occ config:app:get stackiq archimate_import_status # Clear import status if needed -docker exec -u 33 nextcloud php occ config:app:delete softwarecatalog archimate_import_status +docker exec -u 33 nextcloud php occ config:app:delete stackiq archimate_import_status # Check if import is in progress -docker exec -u 33 nextcloud php occ config:app:get softwarecatalog archimate_import_status | grep '"status"' | grep '"running"' +docker exec -u 33 nextcloud php occ config:app:get stackiq archimate_import_status | grep '"status"' | grep '"running"' ``` #### 4. Database Verification @@ -69,10 +69,10 @@ docker exec database-mysql mysql -u nextcloud -pnextcloud nextcloud -e "SELECT u ##### Check Import Logs ```bash # View real-time import logs -docker logs -f nextcloud | grep -E "ArchiMate|SoftwareCatalog|SYNCHRONOUS|batch|saveObjects" +docker logs -f nextcloud | grep -E "ArchiMate|Stackiq|SYNCHRONOUS|batch|saveObjects" # View specific error logs -docker logs nextcloud | grep -E "Error|Exception|Failed" | grep -E "ArchiMate|SoftwareCatalog" | tail -20 +docker logs nextcloud | grep -E "Error|Exception|Failed" | grep -E "ArchiMate|Stackiq" | tail -20 # Check for specific processing steps docker logs nextcloud | grep -E "Starting synchronous|Completed processing|batch save" | tail -10 @@ -83,7 +83,7 @@ docker logs nextcloud | grep -E "Starting synchronous|Completed processing|batch 1. **Import Already Running** ```bash # Clear import status to allow new import - docker exec -u 33 nextcloud php occ config:app:delete softwarecatalog archimate_import_status + docker exec -u 33 nextcloud php occ config:app:delete stackiq archimate_import_status ``` 2. **No Objects Created** @@ -104,20 +104,20 @@ docker logs nextcloud | grep -E "Starting synchronous|Completed processing|batch #### 6. Import Configuration ```bash # Check AMEF configuration -docker exec -u 33 nextcloud php occ config:app:get softwarecatalog amef_config +docker exec -u 33 nextcloud php occ config:app:get stackiq amef_config # Check schema mappings -docker exec -u 33 nextcloud php occ config:app:get softwarecatalog amef_schema_mappings +docker exec -u 33 nextcloud php occ config:app:get stackiq amef_schema_mappings # Verify register and schema IDs -docker exec -u 33 nextcloud php occ config:app:get softwarecatalog amef_register_id -docker exec -u 33 nextcloud php occ config:app:get softwarecatalog amef_schema_ids +docker exec -u 33 nextcloud php occ config:app:get stackiq amef_register_id +docker exec -u 33 nextcloud php occ config:app:get stackiq amef_schema_ids ``` #### 7. Performance Testing ```bash # Test with different batch sizes -docker exec -it nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" \ +docker exec -it nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import" \ -u admin:admin \ -F "archiMateFile=@/var/www/html/data/admin/files/GEMMA_smaller.xml" \ -F "batch_size=50" \ @@ -152,7 +152,7 @@ docker stats nextcloud --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage 4. **❌ DO NOT** test import without clearing previous status - Import status must be cleared if previous import failed - - Use `docker exec -u 33 nextcloud php occ config:app:delete softwarecatalog archimate_import_status` + - Use `docker exec -u 33 nextcloud php occ config:app:delete stackiq archimate_import_status` 5. **❌ DO NOT** ignore memory usage during large imports - Monitor Docker container memory usage diff --git a/.cursorrules b/.cursorrules index c17ba19e..4c31fbb1 100644 --- a/.cursorrules +++ b/.cursorrules @@ -54,12 +54,12 @@ docker-compose exec nextcloud curl -X PUT "http://localhost/index.php/apps/openr #### 4. Check EventListener logs ```bash -docker-compose exec nextcloud tail -n 100 /var/www/html/data/nextcloud.log | grep -i "softwarecatalog" +docker-compose exec nextcloud tail -n 100 /var/www/html/data/nextcloud.log | grep -i "stackiq" ``` #### 5. Check configuration ```bash -docker-compose exec -u 33 nextcloud php occ config:app:get softwarecatalog voorzieningen_organisatie_schema +docker-compose exec -u 33 nextcloud php occ config:app:get stackiq voorzieningen_organisatie_schema ``` ### Expected Behavior diff --git a/.forgejo/workflows/app-tests-live.yml b/.forgejo/workflows/app-tests-live.yml index 4ef96cc7..282adba7 100644 --- a/.forgejo/workflows/app-tests-live.yml +++ b/.forgejo/workflows/app-tests-live.yml @@ -1,14 +1,14 @@ -# app-tests-live.yml — softwarecatalog caller for the LIVE-NC reusable workflow. +# app-tests-live.yml — stackiq caller for the LIVE-NC reusable workflow. # # Boots a real, seeded Nextcloud (db + NC + openregister deployed/enabled + -# softwarecatalog deployed/enabled), then runs the deep Playwright e2e +# stackiq deployed/enabled), then runs the deep Playwright e2e # (tests/e2e/workflows/) and/or the Newman API-contract suite against it as # HARD gates. Generalised per GAP-2 (arm CI live-gating) from openregister's # reference rig; the reusable tests-live.yml is byte-identical fleet-wide, only # these inputs differ. Additive — does not touch app-tests.yml / release / # pre-merge workflows. # -# Gate status for softwarecatalog (see TESTING-CI-ROLLOUT.md for the evidence table): +# Gate status for stackiq (see TESTING-CI-ROLLOUT.md for the evidence table): # deep-e2e: true — e2e RESOLVES register+schema at runtime from /api/voorzieningen/config — CI-portable # newman: true — ARMED: the collection "0. Setup / Preflight" request resolves the register # numeric id from the stable slug 'voorzieningen' (and addresses the org/contact/ @@ -38,7 +38,7 @@ jobs: live: uses: ./.forgejo/workflows/tests-live.yml with: - app-id: softwarecatalog + app-id: stackiq is-openregister: false run-e2e: true run-newman: true diff --git a/.forgejo/workflows/app-tests.yml b/.forgejo/workflows/app-tests.yml index cc027389..f68d5ac3 100644 --- a/.forgejo/workflows/app-tests.yml +++ b/.forgejo/workflows/app-tests.yml @@ -1,4 +1,4 @@ -# app-tests.yml — softwarecatalog caller for the reusable feature-test workflow. +# app-tests.yml — stackiq caller for the reusable feature-test workflow. # # Runs the PHASE-5 testing layers on every PR to the protected branches. # phpunit-unit + l10n-check HARD-GATE; e2e/newman are scaffolded and opt-in @@ -29,6 +29,6 @@ jobs: tests: uses: ./.forgejo/workflows/tests.yml with: - app-id: softwarecatalog + app-id: stackiq run-e2e: ${{ github.event.inputs.run-e2e == 'true' }} run-newman: ${{ github.event.inputs.run-newman == 'true' }} diff --git a/.forgejo/workflows/documentation.yml b/.forgejo/workflows/documentation.yml index d8e3a7ce..a2e2429a 100644 --- a/.forgejo/workflows/documentation.yml +++ b/.forgejo/workflows/documentation.yml @@ -21,5 +21,12 @@ jobs: if: github.event_name != 'pull_request' uses: Conduction/.github/.forgejo/workflows/documentation-deploy.yml@main with: - cf-project-name: softwarecatalog-docs + # FROZEN through the stackiq -> stackiq app-id rename. + # This names an EXISTING Cloudflare Pages project. Renaming it here does + # not rename the project — the deploy simply targets a project that does + # not exist, and a Pages deploy against an unknown project reports success + # while reaching nobody (see the two green Cloudflare deploys that shipped + # to nothing during the fleet rename). Rename the Cloudflare project first, + # then this line. + cf-project-name: stackiq-docs secrets: inherit diff --git a/.forgejo/workflows/release-beta.yml b/.forgejo/workflows/release-beta.yml index 5ada7134..0d75d0f3 100644 --- a/.forgejo/workflows/release-beta.yml +++ b/.forgejo/workflows/release-beta.yml @@ -9,7 +9,7 @@ jobs: release: uses: Conduction/.github/.forgejo/workflows/release-beta.yml@main with: - app-name: softwarecatalog + app-name: stackiq secrets: CODEBERG_TOKEN: ${{ secrets.CODEBERG_TOKEN }} NEXTCLOUD_SIGNING_KEY: ${{ secrets.NEXTCLOUD_SIGNING_KEY }} diff --git a/.forgejo/workflows/release-stable.yml b/.forgejo/workflows/release-stable.yml index b359397b..6fe5d23c 100644 --- a/.forgejo/workflows/release-stable.yml +++ b/.forgejo/workflows/release-stable.yml @@ -9,5 +9,5 @@ jobs: release: uses: Conduction/.github/.forgejo/workflows/release-semrel.yml@main with: - app-name: softwarecatalog + app-name: stackiq secrets: inherit diff --git a/.github/docker-compose.ci.yml b/.github/docker-compose.ci.yml index 4194657f..b4dedba7 100644 --- a/.github/docker-compose.ci.yml +++ b/.github/docker-compose.ci.yml @@ -20,7 +20,7 @@ volumes: services: db: image: pgvector/pgvector:pg16 - container_name: softwarecatalog-ci-db + container_name: stackiq-ci-db environment: POSTGRES_DB: nextcloud POSTGRES_USER: nextcloud @@ -62,4 +62,4 @@ services: networks: default: - name: softwarecatalog-ci-network + name: stackiq-ci-network diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 20937988..7fb79c13 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -117,7 +117,7 @@ jobs: quality: uses: ConductionNL/.github/.github/workflows/quality.yml@main with: - app-name: softwarecatalog + app-name: stackiq php-version: "8.3" # THE LIST IS THE WHOLE DECLARED RANGE. appinfo/info.xml declares # , so 32, 33 and 34 each get @@ -171,7 +171,7 @@ jobs: # declares only `smoke` + `chromium`. enable-playwright: true playwright-test-path: tests/e2e - # `occ app:enable softwarecatalog` runs InitializeSettings, but that + # `occ app:enable stackiq` runs InitializeSettings, but that # repair step has no user session (OpenRegister RBAC can deny it), # swallows its own exception as a warning, and imports with # `force: false` — so a fresh install can come up with no `voorzieningen` @@ -179,7 +179,7 @@ jobs: # explicitly over the admin API and fails loudly if the registers, # schemas, or the app's own register→schema mapping still aren't there. # cwd for this step is the Nextcloud server root. - playwright-seed-command: 'bash apps/softwarecatalog/tests/e2e/ci-seed.sh' + playwright-seed-command: 'bash apps/stackiq/tests/e2e/ci-seed.sh' # Integration Tests (Newman) stays OFF here, deliberately. The # `enable-newman: false` further up is not a default nobody chose: it diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 1de66271..a74f8b36 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -29,4 +29,11 @@ jobs: packages: write uses: ConductionNL/.github/.github/workflows/documentation.yml@main with: + # FROZEN through the stackiq -> stackiq app-id rename. + # `softwarecatalog.conduction.nl` answers 200 today; `stackiq.conduction.nl` + # answers 000 (no DNS record). A CNAME is not a name we own in this repo — + # it is a claim about a record that exists. Publishing docs at a host that + # resolves to nothing takes the documentation site OFFLINE, which is a + # regression, not a rename. Move this only after DNS + the Pages/Cloudflare + # binding for the new host are live, in a change that verifies both. cname: softwarecatalog.conduction.nl diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index ac9a743c..d188b67f 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -23,7 +23,7 @@ jobs: contents: read uses: ConductionNL/.github/.github/workflows/issue-triage.yml@main with: - app-name: softwarecatalog + app-name: stackiq backlog-existing: ${{ github.event_name == 'workflow_dispatch' && inputs.backlog-existing || false }} secrets: PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }} diff --git a/.github/workflows/openspec-sync.yml b/.github/workflows/openspec-sync.yml index 541e3221..96e43482 100644 --- a/.github/workflows/openspec-sync.yml +++ b/.github/workflows/openspec-sync.yml @@ -18,6 +18,6 @@ jobs: contents: read uses: ConductionNL/.github/.github/workflows/openspec-sync.yml@main with: - app-name: softwarecatalog + app-name: stackiq secrets: PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c488856..80bfc8a2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,7 +46,7 @@ jobs: uses: ConductionNL/.github/.github/workflows/release.yml@main with: release-type: unstable - app-name: softwarecatalog + app-name: stackiq secrets: inherit beta: @@ -58,7 +58,7 @@ jobs: uses: ConductionNL/.github/.github/workflows/release.yml@main with: release-type: beta - app-name: softwarecatalog + app-name: stackiq secrets: inherit stable: @@ -70,5 +70,5 @@ jobs: uses: ConductionNL/.github/.github/workflows/release.yml@main with: release-type: stable - app-name: softwarecatalog + app-name: stackiq secrets: inherit diff --git a/AMEF_TESTING.md b/AMEF_TESTING.md index 0da69fed..f262ef57 100644 --- a/AMEF_TESTING.md +++ b/AMEF_TESTING.md @@ -246,7 +246,7 @@ A comprehensive testing script `full_circle_test.php` automates the entire round ```bash # Run complete round-trip test -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/full_circle_test.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/full_circle_test.php ``` #### Test Flow @@ -316,16 +316,16 @@ Individual debug scripts for specific issues: ```bash # Debug XML property structure -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/debug_properties_structure.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/debug_properties_structure.php # Debug conversion flow -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/debug_conversion_flow.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/debug_conversion_flow.php # Debug database content -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/debug_db.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/debug_db.php # Compare XML files -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/compare_archimate.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/compare_archimate.php ``` ## API Testing Procedures @@ -343,18 +343,18 @@ docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/compa ```bash # Upload file from host to container cd /home/rubenlinde/nextcloud-docker-dev -curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" \ +curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import" \ -u admin:admin \ - -F "archiMateFile=@workspace/server/apps-extra/softwarecatalog/lib/Settings/GEMMA_smaller.xml" + -F "archiMateFile=@workspace/server/apps-extra/stackiq/lib/Settings/GEMMA_smaller.xml" ``` #### Method 3: Container-based Testing ```bash # Copy test file to container -docker-compose exec nextcloud cp /var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_smaller.xml /tmp/ +docker-compose exec nextcloud cp /var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_smaller.xml /tmp/ # Test from within container -docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" \ +docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import" \ -u admin:admin \ -F "archiMateFile=@/tmp/GEMMA_smaller.xml" ``` @@ -364,7 +364,7 @@ docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/soft #### Basic Export ```bash # Export all data to ArchiMate format -curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/export" \ +curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/export" \ -u admin:admin \ -H "Content-Type: application/json" \ -d '{ @@ -378,7 +378,7 @@ curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/expo #### Organization-Specific Export ```bash # Export data for specific organization -curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/export" \ +curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/export" \ -u admin:admin \ -H "Content-Type: application/json" \ -d '{ @@ -393,7 +393,7 @@ curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/expo ```bash # Download exported ArchiMate file curl -u admin:admin \ - "http://localhost/index.php/apps/softwarecatalog/api/archimate/download/exported_file.xml" \ + "http://localhost/index.php/apps/stackiq/api/archimate/download/exported_file.xml" \ -o downloaded_file.xml ``` @@ -405,19 +405,19 @@ The API has been refactored for better performance by separating concerns: #### 1. Basic Settings (Fast - ~100ms) ```bash # Get basic configuration only (no object counts) -curl -u admin:admin "http://localhost/index.php/apps/softwarecatalog/api/settings" +curl -u admin:admin "http://localhost/index.php/apps/stackiq/api/settings" ``` #### 2. ArchiMate Status (Medium - ~200ms) ```bash # Get ArchiMate import/export status only (no object counts) -curl -u admin:admin "http://localhost/index.php/apps/softwarecatalog/api/settings/archimate" +curl -u admin:admin "http://localhost/index.php/apps/stackiq/api/settings/archimate" ``` #### 3. Object Counts (Slow - Load on demand) ```bash # Get object counts for all registers (separate endpoint) -curl -u admin:admin "http://localhost/index.php/apps/softwarecatalog/api/settings/objects" +curl -u admin:admin "http://localhost/index.php/apps/stackiq/api/settings/objects" ``` ### Performance Benefits @@ -428,10 +428,10 @@ curl -u admin:admin "http://localhost/index.php/apps/softwarecatalog/api/setting ### Status Polling (Updated) ```bash # Check ArchiMate import/export status for real-time monitoring -curl -u admin:admin "http://localhost/index.php/apps/softwarecatalog/api/settings/archimate" | jq '.archimate' +curl -u admin:admin "http://localhost/index.php/apps/stackiq/api/settings/archimate" | jq '.archimate' # Check object counts when needed for statistics -curl -u admin:admin "http://localhost/index.php/apps/softwarecatalog/api/settings/objects" | jq '.objectCounts' +curl -u admin:admin "http://localhost/index.php/apps/stackiq/api/settings/objects" | jq '.objectCounts' ``` ## Performance Testing @@ -452,7 +452,7 @@ echo 'Peak: ' . round(memory_get_peak_usage(true) / 1024 / 1024, 2) . ' MB' . PH ### 2. Processing Time Measurement ```bash # Test processing time for different file sizes -time curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" \ +time curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import" \ -u admin:admin \ -F "archiMateFile=@lib/Settings/GEMMA_smaller.xml" ``` @@ -510,13 +510,13 @@ The issue occurs somewhere between `extractProperties()` and database storage. I ```bash # Test property extraction in isolation -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/debug_properties_structure.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/debug_properties_structure.php # Test conversion flow -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/debug_conversion_flow.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/debug_conversion_flow.php # Check actual database content -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/debug_db.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/debug_db.php ``` #### Key Findings @@ -589,7 +589,7 @@ if (isset($data['organizations']['item'])) { ```bash # Check if organizations section exists in parsed XML docker-compose exec nextcloud php -r " -\$xml = file_get_contents('/var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml'); +\$xml = file_get_contents('/var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml'); echo 'Organizations section: ' . (strpos(\$xml, '') !== false ? 'FOUND' : 'NOT FOUND') . PHP_EOL; " @@ -609,17 +609,17 @@ echo 'Organizations section: ' . (strpos(\$xml, '') !== false ? ' ### 1. Log Analysis ```bash # View real-time logs during import -docker-compose logs -f nextcloud | grep -i "softwarecatalog\|archimate" +docker-compose logs -f nextcloud | grep -i "stackiq\|archimate" # Check Nextcloud application logs -docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -i "softwarecatalog" +docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -i "stackiq" ``` ### 2. XML Parsing Debug ```bash # Test XML parsing independently docker-compose exec nextcloud php -r " -\$content = file_get_contents('/var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_smaller.xml'); +\$content = file_get_contents('/var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_smaller.xml'); \$xml = simplexml_load_string(\$content); echo 'XML loaded: ' . (\$xml ? 'SUCCESS' : 'FAILED') . PHP_EOL; echo 'Root element: ' . \$xml->getName() . PHP_EOL; @@ -629,7 +629,7 @@ echo 'Root element: ' . \$xml->getName() . PHP_EOL; ### 3. Database State Verification ```bash # Check if objects were created in database -docker-compose exec nextcloud php occ app:execute softwarecatalog --debug-import-status +docker-compose exec nextcloud php occ app:execute stackiq --debug-import-status ``` ## Error Handling Testing @@ -638,7 +638,7 @@ docker-compose exec nextcloud php occ app:execute softwarecatalog --debug-import ```bash # Test with malformed XML echo 'xml' > /tmp/invalid.xml -curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" \ +curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import" \ -u admin:admin \ -F "archiMateFile=@/tmp/invalid.xml" ``` diff --git a/ARCHIMATE_IMPORT_FIX.md b/ARCHIMATE_IMPORT_FIX.md index 6f4749ff..8f3addff 100644 --- a/ARCHIMATE_IMPORT_FIX.md +++ b/ARCHIMATE_IMPORT_FIX.md @@ -61,12 +61,12 @@ Before testing, ensure AMEF configuration is properly set: ```bash # Check AMEF configuration -docker-compose exec -u 33 nextcloud php occ config:app:get softwarecatalog amef_config +docker-compose exec -u 33 nextcloud php occ config:app:get stackiq amef_config # Check via API curl -u 'admin:admin' \ -H 'OCS-APIREQUEST: true' \ - 'http://localhost/index.php/apps/softwarecatalog/api/settings/debug' + 'http://localhost/index.php/apps/stackiq/api/settings/debug' ``` ### 2. Test Import via UI @@ -81,7 +81,7 @@ curl -u 'admin:admin' \ curl -u 'admin:admin' \ -H 'OCS-APIREQUEST: true' \ -F 'archiMateFile=@/path/to/GEMMA_release.xml' \ - 'http://localhost/index.php/apps/softwarecatalog/api/archimate/import' + 'http://localhost/index.php/apps/stackiq/api/archimate/import' ``` ### 4. Monitor Logs @@ -130,7 +130,7 @@ docker logs master-nextcloud-1 | grep -E 'Object creation completed|Object updat ### 1. Check Object Creation ```bash # Check if objects were created in the database -docker-compose exec -u 33 nextcloud php occ config:app:get softwarecatalog amef_config +docker-compose exec -u 33 nextcloud php occ config:app:get stackiq amef_config ``` ### 2. Verify Schema Mapping @@ -150,7 +150,7 @@ The fix ensures that: 1. **Check AMEF Configuration**: ```bash - docker-compose exec -u 33 nextcloud php occ config:app:get softwarecatalog amef_config + docker-compose exec -u 33 nextcloud php occ config:app:get stackiq amef_config ``` Ensure all schema IDs are properly set. diff --git a/ARCHIMATE_PROJECT_STATUS.md b/ARCHIMATE_PROJECT_STATUS.md index 3294a64c..aa4cc3f9 100644 --- a/ARCHIMATE_PROJECT_STATUS.md +++ b/ARCHIMATE_PROJECT_STATUS.md @@ -1,7 +1,7 @@ # ArchiMate Import/Export Project Status ## Project Overview -The ArchiMate Import/Export functionality for the Nextcloud SoftwareCatalog app enables importing architectural models from ArchiMate Exchange Format (AMEF) files and exporting OpenRegister objects back to ArchiMate format. +The ArchiMate Import/Export functionality for the Nextcloud Stackiq app enables importing architectural models from ArchiMate Exchange Format (AMEF) files and exporting OpenRegister objects back to ArchiMate format. ## Current Status: ✅ COMPLETE - PRODUCTION READY @@ -84,7 +84,7 @@ The ArchiMate Import/Export functionality for the Nextcloud SoftwareCatalog app - **File Handling**: Direct file processing without complex framework abstractions - **Progress Tracking**: Server-Sent Events for real-time updates -#### Frontend (`src/views/settings/SoftwareCatalogSettings.vue`) +#### Frontend (`src/views/settings/StackiqSettings.vue`) - **Performance Dashboard**: Real-time performance metrics and timing breakdown - **Visual Analytics**: Progress bars, timing charts, and bottleneck identification - **Configuration**: Batch size and processing method configuration @@ -146,25 +146,25 @@ $options = [ #### Basic Settings (Fast - ~100ms) ```bash -GET /apps/softwarecatalog/api/settings +GET /apps/stackiq/api/settings ``` Returns basic configuration without object counts for fast loading. #### ArchiMate Status (Medium - ~200ms) ```bash -GET /apps/softwarecatalog/api/settings/archimate +GET /apps/stackiq/api/settings/archimate ``` Returns ArchiMate import/export status for real-time polling. #### Object Counts (Slow - Load on demand) ```bash -GET /apps/softwarecatalog/api/settings/objects +GET /apps/stackiq/api/settings/objects ``` Returns object counts for all registers when needed for statistics. ### Import ```bash -POST /apps/softwarecatalog/api/archimate/import +POST /apps/stackiq/api/archimate/import Content-Type: multipart/form-data Parameters: @@ -176,7 +176,7 @@ Parameters: ### Export ```bash -POST /apps/softwarecatalog/api/archimate/export +POST /apps/stackiq/api/archimate/export Content-Type: application/json { @@ -215,13 +215,13 @@ Content-Type: application/json ```bash # Import test (small file) cd /home/rubenlinde/nextcloud-docker-dev -docker exec -it -u 33 master-nextcloud-1 bash -c "curl -X POST 'http://localhost/index.php/apps/softwarecatalog/api/archimate/import' -u admin:admin -F 'archiMateFile=@/var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_smaller.xml' -F 'updateExisting=true' -F 'preserveIds=true'" +docker exec -it -u 33 master-nextcloud-1 bash -c "curl -X POST 'http://localhost/index.php/apps/stackiq/api/archimate/import' -u admin:admin -F 'archiMateFile=@/var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_smaller.xml' -F 'updateExisting=true' -F 'preserveIds=true'" # Import test (production file) -docker exec -it -u 33 master-nextcloud-1 bash -c "curl -X POST 'http://localhost/index.php/apps/softwarecatalog/api/archimate/import' -u admin:admin -F 'archiMateFile=@/var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml' -F 'updateExisting=true' -F 'preserveIds=true'" +docker exec -it -u 33 master-nextcloud-1 bash -c "curl -X POST 'http://localhost/index.php/apps/stackiq/api/archimate/import' -u admin:admin -F 'archiMateFile=@/var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml' -F 'updateExisting=true' -F 'preserveIds=true'" # Export test -docker exec -it -u 33 master-nextcloud-1 bash -c "curl -X POST 'http://localhost/index.php/apps/softwarecatalog/api/archimate/export' -u admin:admin -H 'Content-Type: application/json' -d '{\"format\":\"xml\",\"includeRelationships\":true,\"includeViews\":true}'" +docker exec -it -u 33 master-nextcloud-1 bash -c "curl -X POST 'http://localhost/index.php/apps/stackiq/api/archimate/export' -u admin:admin -H 'Content-Type: application/json' -d '{\"format\":\"xml\",\"includeRelationships\":true,\"includeViews\":true}'" ``` ## Troubleshooting diff --git a/BUG_FIX_ORGANISATION_USER_ASSIGNMENT.md b/BUG_FIX_ORGANISATION_USER_ASSIGNMENT.md index 987fb51b..91c0267a 100644 --- a/BUG_FIX_ORGANISATION_USER_ASSIGNMENT.md +++ b/BUG_FIX_ORGANISATION_USER_ASSIGNMENT.md @@ -32,7 +32,7 @@ The fix adds logic to ensure that: ### Code Changes -**File**: `softwarecatalog/lib/Service/SoftwareCatalogue/ContactPersonHandler.php` +**File**: `stackiq/lib/Service/Stackique/ContactPersonHandler.php` #### 1. Updated `addUserToOrganizationEntity()` Method @@ -60,7 +60,7 @@ This new private method: ### Prerequisites 1. Access to a development environment with: - - Nextcloud with OpenRegister and SoftwareCatalog apps installed + - Nextcloud with OpenRegister and Stackiq apps installed - Docker containers running (nextcloud and database) - Admin access to Nextcloud @@ -178,7 +178,7 @@ docker logs | grep "ContactPersonHandler: Creating organiz ### Rollback If issues occur, the changes can be reverted by restoring the previous version of: -- `softwarecatalog/lib/Service/SoftwareCatalogue/ContactPersonHandler.php` +- `stackiq/lib/Service/Stackique/ContactPersonHandler.php` ## Additional Notes @@ -190,7 +190,7 @@ If issues occur, the changes can be reverted by restoring the previous version o ### Related Files -- `softwarecatalog/lib/Service/SoftwareCatalogue/ContactPersonHandler.php` - Main fix +- `stackiq/lib/Service/Stackique/ContactPersonHandler.php` - Main fix - `openregister/lib/Service/OrganisationService.php` - Used for entity creation - `openregister/lib/Db/OrganisationMapper.php` - Database operations @@ -209,5 +209,5 @@ If issues occur, the changes can be reverted by restoring the previous version o - Issue: Users created from contactpersonen added to wrong organisation - Related: OpenRegister multi-tenancy system -- Related: SoftwareCatalog organisation management +- Related: Stackiq organisation management diff --git a/CIRCLE_TEST_DOCUMENTATION.md b/CIRCLE_TEST_DOCUMENTATION.md index 980adb7f..be06f582 100644 --- a/CIRCLE_TEST_DOCUMENTATION.md +++ b/CIRCLE_TEST_DOCUMENTATION.md @@ -14,27 +14,27 @@ Achieve perfect round-trip data integrity: `GEMMA_release.xml` → Import → Ex ### 1. Cancel Any Running Import ```bash -cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import/cancel" -u admin:admin +cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import/cancel" -u admin:admin ``` ### 2. Run Fresh Import ```bash -cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" -H "Content-Type: application/json" -u admin:admin -d '{"file_path": "/var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml"}' +cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import" -H "Content-Type: application/json" -u admin:admin -d '{"file_path": "/var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml"}' ``` ### 3. Check Database Content (Debug) ```bash -cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/debug_db.php +cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/debug_db.php ``` ### 4. Run Export ```bash -cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/export" -H "Content-Type: application/json" -u admin:admin +cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/export" -H "Content-Type: application/json" -u admin:admin ``` ### 5. Run Comparison Script ```bash -cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/compare_archimate.php +cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/compare_archimate.php ``` **What it does:** @@ -54,19 +54,19 @@ The API has been refactored for better performance by separating concerns: #### 1. Basic Settings (Fast) ```bash # Get basic configuration only (no object counts) -curl -u admin:admin "http://localhost/index.php/apps/softwarecatalog/api/settings" +curl -u admin:admin "http://localhost/index.php/apps/stackiq/api/settings" ``` #### 2. ArchiMate Status (Medium) ```bash # Get ArchiMate import/export status only (no object counts) -curl -u admin:admin "http://localhost/index.php/apps/softwarecatalog/api/settings/archimate" +curl -u admin:admin "http://localhost/index.php/apps/stackiq/api/settings/archimate" ``` #### 3. Object Counts (Slow - Load on demand) ```bash # Get object counts for all registers (separate endpoint) -curl -u admin:admin "http://localhost/index.php/apps/softwarecatalog/api/settings/objects" +curl -u admin:admin "http://localhost/index.php/apps/stackiq/api/settings/objects" ``` ### Performance Benefits @@ -114,13 +114,13 @@ curl -u admin:admin "http://localhost/index.php/apps/softwarecatalog/api/setting ### Compare File Sizes ```bash -cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud ls -lh /var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml /tmp/exported_archimate.xml +cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud ls -lh /var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml /tmp/exported_archimate.xml ``` ### Check XML Structure ```bash # Original structure -docker-compose exec nextcloud head -20 /var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml +docker-compose exec nextcloud head -20 /var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml # Exported structure docker-compose exec nextcloud head -20 /tmp/exported_archimate.xml @@ -129,7 +129,7 @@ docker-compose exec nextcloud head -20 /tmp/exported_archimate.xml ### Find Element Samples ```bash # Original element structure -docker-compose exec nextcloud grep -A 5 -B 5 "element.*identifier" /var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml | head -20 +docker-compose exec nextcloud grep -A 5 -B 5 "element.*identifier" /var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml | head -20 # Exported element structure docker-compose exec nextcloud grep -A 5 -B 5 "" /var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml +docker-compose exec nextcloud grep -A 3 -B 3 "" /var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml # Exported relationships docker-compose exec nextcloud grep -A 10 "" /tmp/exported_archimate.xml @@ -205,19 +205,19 @@ Relationships section exists but content needs verification. ## 🧪 **Complete Test Sequence** -1. **Fresh Import**: `curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" -H "Content-Type: application/json" -u admin:admin -d '{"file_path": "/var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml"}'` +1. **Fresh Import**: `curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import" -H "Content-Type: application/json" -u admin:admin -d '{"file_path": "/var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml"}'` -2. **Test Export**: `curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/export" -H "Content-Type: application/json" -u admin:admin -d '{"format":"archimate","includeRelationships":true,"includeViews":true,"organizationSpecific":false,"selectedSchemas":[]}' -o /tmp/test_export.xml` +2. **Test Export**: `curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/export" -H "Content-Type: application/json" -u admin:admin -d '{"format":"archimate","includeRelationships":true,"includeViews":true,"organizationSpecific":false,"selectedSchemas":[]}' -o /tmp/test_export.xml` -3. **Run Comparison**: `php /var/www/html/apps-extra/softwarecatalog/compare_archimate.php` +3. **Run Comparison**: `php /var/www/html/apps-extra/stackiq/compare_archimate.php` -4. **Full Circle Test**: `php /var/www/html/apps-extra/softwarecatalog/full_circle_test.php` +4. **Full Circle Test**: `php /var/www/html/apps-extra/stackiq/full_circle_test.php` ## 🔍 **Comparison Script Details** ### Usage ```bash -cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/compare_archimate.php +cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/compare_archimate.php ``` ### What It Analyzes diff --git a/FIX_VERIFICATION_SUMMARY.md b/FIX_VERIFICATION_SUMMARY.md index c0abd3e1..cb791c34 100644 --- a/FIX_VERIFICATION_SUMMARY.md +++ b/FIX_VERIFICATION_SUMMARY.md @@ -16,7 +16,7 @@ Modified `ContactPersonHandler.php` to: ## Test Results ### Automated Test Execution -- **Test Script**: `softwarecatalog/test_organisation_user_fix.sh` +- **Test Script**: `stackiq/test_organisation_user_fix.sh` - **Test Run**: Successful - **Exit Code**: 0 @@ -71,7 +71,7 @@ Users: ["testuser1760447692@test.nl"] ## Code Changes ### File Modified -`softwarecatalog/lib/Service/SoftwareCatalogue/ContactPersonHandler.php` +`stackiq/lib/Service/Stackique/ContactPersonHandler.php` ### Methods Changed 1. **`addUserToOrganizationEntity()`** @@ -166,10 +166,10 @@ The bug fix successfully resolves the issue of users being added to the wrong or ## Files Changed -1. `softwarecatalog/lib/Service/SoftwareCatalogue/ContactPersonHandler.php` - Main fix -2. `softwarecatalog/BUG_FIX_ORGANISATION_USER_ASSIGNMENT.md` - Documentation -3. `softwarecatalog/test_organisation_user_fix.sh` - Automated test script -4. `softwarecatalog/FIX_VERIFICATION_SUMMARY.md` - This file +1. `stackiq/lib/Service/Stackique/ContactPersonHandler.php` - Main fix +2. `stackiq/BUG_FIX_ORGANISATION_USER_ASSIGNMENT.md` - Documentation +3. `stackiq/test_organisation_user_fix.sh` - Automated test script +4. `stackiq/FIX_VERIFICATION_SUMMARY.md` - This file ## Sign Off diff --git a/FRONTEND_DEVELOPMENT_GUIDE.md b/FRONTEND_DEVELOPMENT_GUIDE.md index e579f21c..b89c9739 100644 --- a/FRONTEND_DEVELOPMENT_GUIDE.md +++ b/FRONTEND_DEVELOPMENT_GUIDE.md @@ -36,19 +36,19 @@ This guide provides everything needed to implement the frontend for the **levera ### 1. Get Suggestions ```http -GET /index.php/apps/softwarecatalog/api/aangeboden-gebruik/afnemer +GET /index.php/apps/stackiq/api/aangeboden-gebruik/afnemer ``` Returns all suggestions where current organisation is the afnemer. ### 2. Claim Suggestion ```http -PUT /index.php/apps/softwarecatalog/api/aangeboden-gebruik/{id}/set-self +PUT /index.php/apps/stackiq/api/aangeboden-gebruik/{id}/set-self ``` Claims a suggestion (transfers ownership to current organisation). ### 3. Deny Suggestion ```http -DELETE /index.php/apps/softwarecatalog/api/aangeboden-gebruik/{id}/deny +DELETE /index.php/apps/stackiq/api/aangeboden-gebruik/{id}/deny ``` Denies a suggestion (deletes it completely). diff --git a/INTEGRATION_TEST_RESULTS.md b/INTEGRATION_TEST_RESULTS.md index 807b55e9..570e2899 100644 --- a/INTEGRATION_TEST_RESULTS.md +++ b/INTEGRATION_TEST_RESULTS.md @@ -15,14 +15,14 @@ The new `koppelingen-gebruik` API endpoints are fully functional and working as - **PHP Version**: 8.2.29 - **PHPUnit Version**: 10.5.58 - **Test User**: admin/admin -- **SoftwareCatalog App**: Enabled ✓ +- **Stackiq App**: Enabled ✓ - **OpenRegister App**: Enabled ✓ ## API Endpoints Tested ### 1. GET /api/koppelingen-gebruik (List All) -**Endpoint**: `http://localhost/index.php/apps/softwarecatalog/api/koppelingen-gebruik` +**Endpoint**: `http://localhost/index.php/apps/stackiq/api/koppelingen-gebruik` **Test Results**: - ✅ Returns 200 OK @@ -39,13 +39,13 @@ The new `koppelingen-gebruik` API endpoints are fully functional and working as "pages": 2569, "limit": 20, "offset": 0, - "next": "/index.php/apps/softwarecatalog/api/koppelingen-gebruik?page=2" + "next": "/index.php/apps/stackiq/api/koppelingen-gebruik?page=2" } ``` ### 2. GET /api/koppelingen-gebruik (With Pagination) -**Endpoint**: `http://localhost/index.php/apps/softwarecatalog/api/koppelingen-gebruik?_limit=5` +**Endpoint**: `http://localhost/index.php/apps/stackiq/api/koppelingen-gebruik?_limit=5` **Test Results**: - ✅ Limit parameter works correctly @@ -54,7 +54,7 @@ The new `koppelingen-gebruik` API endpoints are fully functional and working as ### 3. GET /api/koppelingen-gebruik/{uuid} (Filter by UUID) -**Endpoint**: `http://localhost/index.php/apps/softwarecatalog/api/koppelingen-gebruik/369634b8-4581-5ce9-967e-b8529dee84bd` +**Endpoint**: `http://localhost/index.php/apps/stackiq/api/koppelingen-gebruik/369634b8-4581-5ce9-967e-b8529dee84bd` **Test Results**: - ✅ UUID filtering works correctly @@ -123,7 +123,7 @@ The new `koppelingen-gebruik` API endpoints are fully functional and working as **Running All Integration Tests**: ```bash -cd /var/www/html/apps-extra/softwarecatalog +cd /var/www/html/apps-extra/stackiq vendor/bin/phpunit --testsuite "Integration Tests" ``` @@ -135,7 +135,7 @@ vendor/bin/phpunit tests/Integration/KoppelingenGebruikIntegrationTest.php **From Docker Container**: ```bash docker exec -u 33 master-nextcloud-1 bash -c \ - "cd /var/www/html/apps-extra/softwarecatalog && \ + "cd /var/www/html/apps-extra/stackiq && \ vendor/bin/phpunit --testsuite 'Integration Tests'" ``` diff --git a/KOPPELINGEN_GEBRUIK_REFACTOR.md b/KOPPELINGEN_GEBRUIK_REFACTOR.md index 69518918..3704bf2f 100644 --- a/KOPPELINGEN_GEBRUIK_REFACTOR.md +++ b/KOPPELINGEN_GEBRUIK_REFACTOR.md @@ -25,21 +25,21 @@ October 29, 2025 ### 2. Code Changes #### routes.php -- **File**: `softwarecatalog/appinfo/routes.php` +- **File**: `stackiq/appinfo/routes.php` - **Changes**: - Removed generic endpoint route - Updated comment to reflect UUID-specific nature - Documented that endpoint supports organisation, module, and application UUIDs #### AangebodenGebruikController.php -- **File**: `softwarecatalog/lib/Controller/AangebodenGebruikController.php` +- **File**: `stackiq/lib/Controller/AangebodenGebruikController.php` - **Changes**: - Removed `getKoppelingenGebruik()` method (lines 131-198) - Kept `getKoppelingenGebruikByUuid()` method - Controller now only handles UUID-specific requests #### AangebodenGebruikService.php -- **File**: `softwarecatalog/lib/Service/AangebodenGebruikService.php` +- **File**: `stackiq/lib/Service/AangebodenGebruikService.php` - **Changes**: - Removed generic `getKoppelingenGebruik()` method - Enhanced docblock for `getKoppelingenGebruikByUuid()` to clarify it handles three UUID types @@ -47,7 +47,7 @@ October 29, 2025 ### 3. Enhanced Integration Tests ✅ -**File**: `softwarecatalog/tests/Integration/KoppelingenGebruikIntegrationTest.php` +**File**: `stackiq/tests/Integration/KoppelingenGebruikIntegrationTest.php` **New Test Data Creation:** - ✅ Creates test organisations (Organisation A and Organisation B) @@ -107,7 +107,7 @@ October 29, 2025 ### 4. Documentation Updates ✅ -**File**: `softwarecatalog/website/docs/aangeboden-gebruik-api.md` +**File**: `stackiq/website/docs/aangeboden-gebruik-api.md` **Changes:** @@ -267,12 +267,12 @@ GET /api/koppelingen-gebruik/{uuid}?organisation={org-uuid} ```bash # From host -cd softwarecatalog +cd stackiq vendor/bin/phpunit tests/Integration/KoppelingenGebruikIntegrationTest.php # From Docker container docker exec -u 33 master-nextcloud-1 bash -c \ - "cd /var/www/html/apps-extra/softwarecatalog && \ + "cd /var/www/html/apps-extra/stackiq && \ vendor/bin/phpunit tests/Integration/KoppelingenGebruikIntegrationTest.php" ``` @@ -287,11 +287,11 @@ docker exec -u 33 master-nextcloud-1 bash -c \ ## Files Modified -1. **✅ softwarecatalog/appinfo/routes.php** - Removed generic endpoint route -2. **✅ softwarecatalog/lib/Controller/AangebodenGebruikController.php** - Removed generic method -3. **✅ softwarecatalog/lib/Service/AangebodenGebruikService.php** - Removed generic method, updated docblocks -4. **✅ softwarecatalog/tests/Integration/KoppelingenGebruikIntegrationTest.php** - Complete rewrite with comprehensive tests -5. **✅ softwarecatalog/website/docs/aangeboden-gebruik-api.md** - Updated to reflect UUID-only endpoint +1. **✅ stackiq/appinfo/routes.php** - Removed generic endpoint route +2. **✅ stackiq/lib/Controller/AangebodenGebruikController.php** - Removed generic method +3. **✅ stackiq/lib/Service/AangebodenGebruikService.php** - Removed generic method, updated docblocks +4. **✅ stackiq/tests/Integration/KoppelingenGebruikIntegrationTest.php** - Complete rewrite with comprehensive tests +5. **✅ stackiq/website/docs/aangeboden-gebruik-api.md** - Updated to reflect UUID-only endpoint ## Linter Status diff --git a/README.md b/README.md index ce2146c3..025da88d 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,23 @@

- Software Catalogus logo + Stackiq logo

-

Software Catalogus

+

Stackiq

GEMMA-compliant software catalog for Nextcloud — applications, modules, and integration management

- Latest release - License - Code quality - Documentation + Latest release + License + Code quality + Documentation

--- -Software Catalogus brings structured software portfolio management to Nextcloud. Register the applications, modules, and connections (koppelingen) that make up your organization's IT landscape, manage contacts and organizations, and synchronize catalog data across a federated open data network — all aligned with Dutch GEMMA standards. +Stackiq brings structured software portfolio management to Nextcloud. Register the applications, modules, and connections (koppelingen) that make up your organization's IT landscape, manage contacts and organizations, and synchronize catalog data across a federated open data network — all aligned with Dutch GEMMA standards. It integrates with [OpenRegister](https://codeberg.org/Conduction/openregister) for data storage and automatic user provisioning, turning register contacts into Nextcloud accounts with role-based group membership. @@ -92,7 +92,7 @@ graph TD ### Directory Structure ``` -softwarecatalog/ +stackiq/ ├── appinfo/ # Nextcloud app manifest, routes, navigation ├── lib/ # PHP backend — controllers, services, event listeners │ ├── Controller/ # API and page controllers @@ -104,7 +104,7 @@ softwarecatalog/ ├── docs/ # Technical documentation ├── img/ # App icons and screenshots ├── l10n/ # Translations (en, nl) -└── docusaurus/ # Product documentation site (softwarecatalog.app) +└── docusaurus/ # Product documentation site (softwarecatalog.conduction.nl) ``` ## Requirements @@ -120,7 +120,7 @@ softwarecatalog/ ### From the Nextcloud App Store 1. Go to **Apps** in your Nextcloud instance -2. Search for **Software Catalogus** +2. Search for **Stackiq** 3. Click **Download and enable** > OpenRegister must be installed first. [Install OpenRegister -->](https://apps.nextcloud.com/apps/openregister) @@ -129,11 +129,11 @@ softwarecatalog/ ```bash cd /var/www/html/custom_apps -git clone https://codeberg.org/Conduction/softwarecatalog.git -cd softwarecatalog +git clone https://github.com/ConductionNL/stackiq.git +cd stackiq npm install npm run build -php occ app:enable softwarecatalog +php occ app:enable stackiq ``` ## Development @@ -147,7 +147,7 @@ docker compose -f openregister/docker-compose.yml up -d ### Frontend development ```bash -cd softwarecatalog +cd stackiq npm install npm run dev # Watch mode npm run build # Production build @@ -180,7 +180,7 @@ npm run stylelint # CSS linting ## Documentation -Full documentation is available at **[softwarecatalog.app](https://softwarecatalog.app)** +Full documentation is available at **[softwarecatalog.conduction.nl](https://softwarecatalog.conduction.nl)** | Page | Description | |------|-------------| @@ -191,11 +191,11 @@ Full documentation is available at **[softwarecatalog.app](https://softwarecatal ## Testing -Software Catalogus is tested through three complementary layers that together provide comprehensive quality assurance. +Stackiq is tested through three complementary layers that together provide comprehensive quality assurance. ### Code Quality (Conduction Quality Workflow) -Every commit runs through the [Conduction quality workflow](https://codeberg.org/Conduction/softwarecatalog/actions) — a strict CI/CD pipeline that enforces: +Every commit runs through the [Conduction quality workflow](https://github.com/ConductionNL/stackiq/actions) — a strict CI/CD pipeline that enforces: - **PHP Lint** — syntax validation - **PHPCS** — coding standards (PEAR + PSR-12 + custom Conduction rules, including forbidden functions and named parameter enforcement) @@ -263,7 +263,7 @@ The master file `issues.md` tracks all 137 IGS (In Review/Scoped) issues with th ## Required Repositories -The Softwarecatalogus is not a standalone application — it runs as a Nextcloud app backed by several other apps, with a separate React-based public frontend. +Stackiq is not a standalone application — it runs as a Nextcloud app backed by several other apps, with a separate React-based public frontend. | Repository | Role | Required | |-----------|------|----------| @@ -305,8 +305,8 @@ docker exec -u www-data nextcloud php occ app:enable opencatalogi # 3. NL Design — theming (no hard dependencies, but should be early) docker exec -u www-data nextcloud php occ app:enable nldesign -# 4. Software Catalogus — depends on OpenRegister and OpenCatalogi -docker exec -u www-data nextcloud php occ app:enable softwarecatalog +# 4. Stackiq — depends on OpenRegister and OpenCatalogi +docker exec -u www-data nextcloud php occ app:enable stackiq # 5. LaunchPad — optional, for dashboard widgets docker exec -u www-data nextcloud php occ app:enable launchpad @@ -314,7 +314,7 @@ docker exec -u www-data nextcloud php occ app:enable launchpad ### 3. Import data -The Softwarecatalogus requires register schemas and seed data to function. Import the configurations via the OpenRegister Magic Mapper: +Stackiq requires register schemas and seed data to function. Import the configurations via the OpenRegister Magic Mapper: ```bash # Import the softwarecatalogus register configuration @@ -323,13 +323,13 @@ The Softwarecatalogus requires register schemas and seed data to function. Impor curl -X POST "http://localhost:8080/index.php/apps/openregister/api/configurations?force=true" \ -u admin:admin \ -H "Content-Type: application/json" \ - -d @softwarecatalog/configurations/softwarecatalogus_register.json + -d @stackiq/lib/Settings/softwarecatalogus_register.json ``` For a complete test environment with users, organizations, and sample data: ```bash -bash softwarecatalog/test-setup.sh +bash stackiq/test-setup.sh ``` This creates 7 test users across 4 organizations (leverancier, gemeente, samenwerking, admin), seeds contact persons and sample applications, and verifies RBAC scoping. @@ -338,7 +338,7 @@ This creates 7 test users across 4 organizations (leverancier, gemeente, samenwe ```bash # Nextcloud app frontend (Vue 2) -cd softwarecatalog && npm install && npm run build +cd stackiq && npm install && npm run build # Public frontend (React) — only needed if not using Docker cd tilburg-woo-ui && yarn install && yarn build diff --git a/README_DEBUG.md b/README_DEBUG.md index 3d67bf22..1367d5d1 100644 --- a/README_DEBUG.md +++ b/README_DEBUG.md @@ -112,7 +112,7 @@ $ occ user:info test.fixed ## Key Fixes Applied ### 1. Username Generation Fix -**File**: `lib/Service/SoftwareCatalogue/ContactPersonHandler.php` +**File**: `lib/Service/Stackiq/ContactPersonHandler.php` **Issue**: `??` operator not working properly **Fix**: Explicit username assignment logic @@ -127,7 +127,7 @@ $ occ user:info test.fixed **Fix**: Changed to use correct `find()` method with register/schema context ### 4. Organization Group Assignment Fix ⭐ **KEY FIX** -**File**: `lib/Service/SoftwareCatalogue/ContactPersonHandler.php` +**File**: `lib/Service/Stackiq/ContactPersonHandler.php` **Lines**: 814, 1175 **Issue**: `$objectService->getObject($organizationId)` method doesn't exist **Fix**: @@ -144,17 +144,17 @@ $organizationObject = $objectService->find($organizationId, [], false, 6, 35); The following debug logging is currently active and should be removed after successful acceptance testing: ### 1. ContactPersonHandler Debug Logs -**File**: `lib/Service/SoftwareCatalogue/ContactPersonHandler.php` +**File**: `lib/Service/Stackiq/ContactPersonHandler.php` **Lines**: ~470-490, ~800-850 **Purpose**: Track user group assignment and organization lookup ### 2. OrganizationHandler Debug Logs -**File**: `lib/Service/SoftwareCatalogue/OrganizationHandler.php` +**File**: `lib/Service/Stackiq/OrganizationHandler.php` **Lines**: Various **Purpose**: Track contactgegevens creation process ### 3. EventListener Debug Logs -**File**: `lib/EventListener/SoftwareCatalogEventListener.php` +**File**: `lib/EventListener/StackiqEventListener.php` **Lines**: Various **Purpose**: Track event processing flow diff --git a/SECURITY.md b/SECURITY.md index 040d94c4..0c0df29b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -46,16 +46,16 @@ For every app `` under [ConductionNL](https://github.com/ConductionNL), two | **Always-latest released SBOM** (auto-redirects to newest release) | `https://github.com/ConductionNL//releases/latest/download/sbom.cdx.json` | | **Specific release SBOM** (pinned, for compliance archives) | `https://github.com/ConductionNL//releases/download//sbom.cdx.json` | -Example — fetch the latest softwarecatalog SBOM: +Example — fetch the latest stackiq SBOM: ```bash -curl -sL https://github.com/ConductionNL/softwarecatalog/releases/latest/download/sbom.cdx.json | jq . +curl -sL https://github.com/ConductionNL/stackiq/releases/latest/download/sbom.cdx.json | jq . ``` Example — fetch the SBOM for a specific historical release: ```bash -curl -sL https://github.com/ConductionNL/softwarecatalog/releases/download/v1.0.0/sbom.cdx.json | jq . +curl -sL https://github.com/ConductionNL/stackiq/releases/download/v1.0.0/sbom.cdx.json | jq . ``` ### Update cadence diff --git a/aanvullende-informatie.md b/aanvullende-informatie.md index f9f97357..a59c6557 100644 --- a/aanvullende-informatie.md +++ b/aanvullende-informatie.md @@ -33,8 +33,8 @@ Het GEMMA ArchiMate Exchange Format bestand bevat het volledige architectuurmode | Bestand | Omschrijving | Pad | |---------|-------------|-----| -| `GEMMA release.xml` | Volledig GEMMA ArchiMate model (13.3 MB) | `softwarecatalog/data/GEMMA release.xml` | -| `GEMMA_release.xml` | Kopie in Settings directory (13.4 MB) | `softwarecatalog/lib/Settings/GEMMA_release.xml` | +| `GEMMA release.xml` | Volledig GEMMA ArchiMate model (13.3 MB) | `stackiq/data/GEMMA release.xml` | +| `GEMMA_release.xml` | Kopie in Settings directory (13.4 MB) | `stackiq/lib/Settings/GEMMA_release.xml` | | Turfbrug test model | VNG Realisatie test-export (15 MB) | `Softwarecatalogus/docs/examples/02-04-2025_GEMMA 2_Turfbrug (test VNG Realisatie)_ameff_model.xml` | ### Analyse: Orphaned buitengemeentelijkVoorziening referenties in koppelingen @@ -264,7 +264,7 @@ Softwarecatalogus/reacties/screenshots/{nummer}-{beschrijving}.png | Frontend URL | http://localhost:3000 | | Backend URL | http://localhost:8080 | | Admin credentials | admin / admin | -| Test-gebruikers | Zie `softwarecatalog/.claude/skills/test-softwarecatalog.md` | +| Test-gebruikers | Zie `stackiq/.claude/skills/test-stackiq.md` | ### Browsergebruik - Gebruik de toegewezen browser (zie browser-pool in CLAUDE.md) @@ -292,7 +292,7 @@ awk -F',' '{if ($NF == "" || $NF == "\"\"") print}' Softwarecatalogus/data/conta ``` ### RBAC-referentie voor agents -De RBAC-regels staan in: `softwarecatalog/lib/Settings/softwarecatalogus_register.json` +De RBAC-regels staan in: `stackiq/lib/Settings/softwarecatalogus_register.json` Raadpleeg dit bestand wanneer een issue gaat over zichtbaarheid, toegang, of organisatie-scoping. ### Voortgang bijhouden diff --git a/appinfo/info.xml b/appinfo/info.xml index 0c68b0f6..9935cc76 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -1,14 +1,14 @@ - softwarecatalog - Software Catalogus - Software Catalogus + stackiq + Stackiq + Stackiq Manage your software portfolio with applications, modules, and connections Beheer je softwareportfolio met applicaties, modules en koppelingen - ⚠️ **Active development — not for production use yet.** This app is under active development. Although it may carry a stable release status, **please do not use it in production environments before 17 June 2026.** See the [app page on conduction.nl](https://conduction.nl/apps/softwarecatalog) for release planning and what this app does. + ⚠️ **Active development — not for production use yet.** This app is under active development. Although it may carry a stable release status, **please do not use it in production environments before 17 June 2026.** See the [app page on conduction.nl](https://conduction.nl/apps/stackiq) for release planning and what this app does. -Software Catalogus brings structured software portfolio management to Nextcloud. Keep track of all the applications, modules, and connections in your organization — and share them across a federated open data network. +Stackiq brings structured software portfolio management to Nextcloud. Keep track of all the applications, modules, and connections in your organization — and share them across a federated open data network. **Key Features** @@ -18,7 +18,7 @@ Software Catalogus brings structured software portfolio management to Nextcloud. - **Contract & license administration** — Track contracts with an approval workflow, renewal status, and expiry alerts - **GEMMA/ArchiMate standards & compliance** — Maintain a standards register, record compliance claims with evidence, cross-check modules against standards in a compliance matrix, and import/export ArchiMate models - **Portfolio roadmap** — See applications in use grouped by lifecycle phase, with end-of-support and phase-out warnings -- **Federated synchronization** — Share and sync catalog data with other Software Catalogus instances via OpenCatalogi's directory network (optional; degrades gracefully if OpenCatalogi is not installed) +- **Federated synchronization** — Share and sync catalog data with other Stackiq instances via OpenCatalogi's directory network (optional; degrades gracefully if OpenCatalogi is not installed) - **Automatic user provisioning** — Sync contacts and organizations from your register into Nextcloud accounts and groups - **Open data publishing** — Publish selected catalog entries for transparency and reuse, with anonymous self-registration and moderation for new organizations @@ -28,9 +28,9 @@ Free and open source under the EUPL license. **Support:** For support, contact support@conduction.nl. For a Service Level Agreement (SLA), contact sales@conduction.nl. ]]> - ⚠️ **In actieve ontwikkeling — nog niet voor productiegebruik.** Deze app is volop in ontwikkeling. Hoewel de app een stabiele release-status kan hebben, **gebruik deze nog niet in productieomgevingen vóór 17 juni 2026.** Zie de [app-pagina op conduction.nl](https://conduction.nl/apps/softwarecatalog) voor release-planning en het doel van deze app. + ⚠️ **In actieve ontwikkeling — nog niet voor productiegebruik.** Deze app is volop in ontwikkeling. Hoewel de app een stabiele release-status kan hebben, **gebruik deze nog niet in productieomgevingen vóór 17 juni 2026.** Zie de [app-pagina op conduction.nl](https://conduction.nl/apps/stackiq) voor release-planning en het doel van deze app. -Software Catalogus brengt gestructureerd softwareportfoliobeheer naar Nextcloud. Houd al je applicaties, modules en koppelingen bij — en deel ze via een gefedereerd open data netwerk. +Stackiq brengt gestructureerd softwareportfoliobeheer naar Nextcloud. Houd al je applicaties, modules en koppelingen bij — en deel ze via een gefedereerd open data netwerk. **Belangrijkste functies** @@ -40,7 +40,7 @@ Software Catalogus brengt gestructureerd softwareportfoliobeheer naar Nextcloud. - **Contract- en licentiebeheer** — Volg contracten met een goedkeuringsworkflow, verlengingsstatus en verloopmeldingen - **GEMMA/ArchiMate-standaarden & compliance** — Beheer een standaardenregister, leg compliance-claims met bewijs vast, toets modules tegen standaarden in een compliance-matrix en importeer/exporteer ArchiMate-modellen - **Portfolioroadmap** — Zie applicaties in gebruik gegroepeerd op levenscyclusfase, met waarschuwingen voor einde ondersteuning en uitfasering -- **Gefedereerde synchronisatie** — Deel en synchroniseer catalogusdata met andere Software Catalogus-instanties via het directorynetwerk van OpenCatalogi (optioneel; werkt zonder OpenCatalogi met beperkte functionaliteit) +- **Gefedereerde synchronisatie** — Deel en synchroniseer catalogusdata met andere Stackiq-instanties via het directorynetwerk van OpenCatalogi (optioneel; werkt zonder OpenCatalogi met beperkte functionaliteit) - **Automatische gebruikersaanmaak** — Synchroniseer contacten en organisaties vanuit je register naar Nextcloud-accounts en -groepen - **Open data publicatie** — Publiceer geselecteerde catalogusitems voor transparantie en hergebruik, met anonieme zelfregistratie en moderatie voor nieuwe organisaties @@ -53,7 +53,7 @@ Vrij en open source onder de EUPL-licentie. 0.1.141-unstable.20260821053703 EUPL-1.2 Conduction - SoftwareCatalog + Stackiq https://github.com/ConductionNL/stackiq https://github.com/ConductionNL/stackiq @@ -73,7 +73,7 @@ Vrij en open source onder de EUPL-licentie. + OCA\Stackiq\Repair\MigrateAppConfigKeys + OCA\Stackiq\Repair\MigrateUserPreferences + + OCA\Stackiq\Repair\MigrateBackgroundJobClasses + - OCA\SoftwareCatalog\Repair\RenameDutchSchemaSlugs - OCA\SoftwareCatalog\Repair\InitializeSettings - OCA\SoftwareCatalog\Repair\MigrateContactsToNc - OCA\SoftwareCatalog\Repair\BackfillContractApprovalState + OCA\Stackiq\Repair\RenameDutchSchemaSlugs + OCA\Stackiq\Repair\InitializeSettings + OCA\Stackiq\Repair\MigrateContactsToNc + OCA\Stackiq\Repair\BackfillContractApprovalState - OCA\SoftwareCatalog\Repair\RenameDutchCatalogColumns + OCA\Stackiq\Repair\RenameDutchCatalogColumns - OCA\SoftwareCatalog\Repair\RenameDutchCatalogValues + OCA\Stackiq\Repair\RenameDutchCatalogValues - OCA\SoftwareCatalog\Repair\InitializeSettings + OCA\Stackiq\Repair\MigrateAppConfigKeys + OCA\Stackiq\Repair\MigrateUserPreferences + OCA\Stackiq\Repair\MigrateBackgroundJobClasses + OCA\Stackiq\Repair\InitializeSettings - OCA\SoftwareCatalog\Settings\SoftwareCatalogAdmin - OCA\SoftwareCatalog\Sections\SoftwareCatalogAdmin + OCA\Stackiq\Settings\StackiqAdmin + OCA\Stackiq\Sections\StackiqAdmin - softwarecatalog - Software Catalogs - softwarecatalog.dashboard.page + stackiq + Stackiq + stackiq.dashboard.page app.svg diff --git a/appinfo/routes.php b/appinfo/routes.php index cabad721..f3034733 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -3,16 +3,16 @@ declare(strict_types=1); /** - * SoftwareCatalog Routes Configuration + * Stackiq Routes Configuration * - * This file defines the API routes for the SoftwareCatalog application. + * This file defines the API routes for the Stackiq application. * * @category Configuration - * @package OCA\SoftwareCatalog + * @package OCA\Stackiq * @version 1.0.0 * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ return [ @@ -27,7 +27,7 @@ // Contract approval delegation to decidesk (in-process IEventDispatcher; fail-closed). // Outcome is projected by DecisionConcludedListener, not an HTTP callback. - // @spec openspec/changes/softwarecatalog-delegation-via-events/specs/contract-decision-delegation/spec.md + // @spec openspec/changes/stackiq-delegation-via-events/specs/contract-decision-delegation/spec.md ['name' => 'contractApproval#config', 'url' => '/api/contracts/approval/config', 'verb' => 'GET'], ['name' => 'contractApproval#submit', 'url' => '/api/contracts/{contractUuid}/approval/submit', 'verb' => 'POST'], ['name' => 'contractApproval#submitRenewal', 'url' => '/api/contracts/{contractUuid}/approval/renewal', 'verb' => 'POST'], @@ -212,7 +212,7 @@ ['name' => 'moderation#approve', 'url' => '/api/moderation/{uuid}/approve', 'verb' => 'POST'], ['name' => 'moderation#reject', 'url' => '/api/moderation/{uuid}/reject', 'verb' => 'POST'], - // CATALOG RATINGS (softwarecatalog#375) — authenticated review + // CATALOG RATINGS (stackiq#375) — authenticated review // submission (author/status always server-stamped, never from the // client) + public approved-only aggregate for module/dienst detail. ['name' => 'review#submit', 'url' => '/api/reviews', 'verb' => 'POST'], @@ -298,7 +298,7 @@ // `dashboard#page` route above: both entries target the same // controller#method, so without a postfix they generate the same // internal route name and the later one silently displaces the first — - // which 404'd the app's own entry point (`/apps/softwarecatalog/`) for + // which 404'd the app's own entry point (`/apps/stackiq/`) for // every user, because this route's `path` requirement ('.+') can never // match an empty path. ['name' => 'dashboard#page', 'url' => '/{path}', 'verb' => 'GET', 'requirements' => ['path' => '.+'], 'defaults' => ['path' => ''], 'postfix' => 'spa'], diff --git a/check_db.php b/check_db.php index b9c94240..3e15716e 100644 --- a/check_db.php +++ b/check_db.php @@ -4,7 +4,7 @@ $db = \OC::$server->getDatabaseConnection(); $query = $db->getQueryBuilder(); $query->select('id', 'slug', 'object') - ->from('softwarecatalog_objects') + ->from('stackiq_objects') ->where($query->expr()->like('id', $query->createNamedParameter('%d4572e2e%'))) ->setMaxResults(1); $result = $query->execute(); diff --git a/check_openregister.php b/check_openregister.php index 70a65895..aa3fa3b2 100644 --- a/check_openregister.php +++ b/check_openregister.php @@ -9,7 +9,7 @@ 'oc_openregister_object', 'openregister_objects', 'objects', - 'oc_softwarecatalog_objects' + 'oc_stackiq_objects' ]; foreach ($possibleTables as $tableName) { diff --git a/check_tables.php b/check_tables.php index f6f4de86..0042fcec 100644 --- a/check_tables.php +++ b/check_tables.php @@ -3,13 +3,13 @@ $db = \OC::$server->getDatabaseConnection(); -// Get all tables that contain 'softwarecatalog' or 'catalog' +// Get all tables that contain 'stackiq' or 'catalog' $query = $db->getQueryBuilder(); $query->select('TABLE_NAME') ->from('information_schema.TABLES') ->where($query->expr()->eq('TABLE_SCHEMA', $query->createNamedParameter('nextcloud'))) ->andWhere($query->expr()->orX( - $query->expr()->like('TABLE_NAME', $query->createNamedParameter('%softwarecatalog%')), + $query->expr()->like('TABLE_NAME', $query->createNamedParameter('%stackiq%')), $query->expr()->like('TABLE_NAME', $query->createNamedParameter('%catalog%')) )); @@ -21,7 +21,7 @@ } if (empty($tables)) { - echo "No tables found containing 'softwarecatalog' or 'catalog'" . PHP_EOL; + echo "No tables found containing 'stackiq' or 'catalog'" . PHP_EOL; // Let's check for any tables that might be related $query2 = $db->getQueryBuilder(); diff --git a/compare_archimate.php b/compare_archimate.php index 15237fe5..ab0ad79c 100644 --- a/compare_archimate.php +++ b/compare_archimate.php @@ -616,13 +616,13 @@ private function generateReport(): void try { $comparator = new ArchiMateComparator(); - $originalFile = '/var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml'; + $originalFile = '/var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml'; $exportedFile = '/tmp/archimate_export_latest.xml'; // First, generate a fresh export echo "Generating fresh export...\n"; $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, 'http://localhost/index.php/apps/softwarecatalog/api/archimate/export'); + curl_setopt($ch, CURLOPT_URL, 'http://localhost/index.php/apps/stackiq/api/archimate/export'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, '{}'); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); diff --git a/composer.json b/composer.json index 880aa7be..499a657b 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "conductionnl/softwarecatalog", + "name": "conductionnl/stackiq", "description": "Quickly build data registers based on schema.json", "license": "EUPL-1.2", "authors": [ @@ -11,7 +11,7 @@ ], "autoload": { "psr-4": { - "OCA\\SoftwareCatalog\\": "lib/" + "OCA\\Stackiq\\": "lib/" } }, "scripts": { diff --git a/css/dashboardWidgets.css b/css/dashboardWidgets.css index adfbc9bc..0dd5005a 100644 --- a/css/dashboardWidgets.css +++ b/css/dashboardWidgets.css @@ -1,8 +1,8 @@ -.icon-softwarecatalog-widget { +.icon-stackiq-widget { background-image: url('../img/app-dark.svg'); filter: var(--background-invert-if-dark); } -body.theme--dark .icon-softwarecatalog-widget { +body.theme--dark .icon-stackiq-widget { background-image: url('../img/app.svg'); } diff --git a/docs/ANONYMOUS_USER_REGISTRATION_USECASE.md b/docs/ANONYMOUS_USER_REGISTRATION_USECASE.md index d4df56f2..e715f5f8 100644 --- a/docs/ANONYMOUS_USER_REGISTRATION_USECASE.md +++ b/docs/ANONYMOUS_USER_REGISTRATION_USECASE.md @@ -243,7 +243,7 @@ curl -u 'admin:admin' 'http://localhost/index.php/apps/openregister/api/organisa docker-compose exec -u 33 nextcloud php /var/www/html/occ user:info {username} # Check logs -docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -E "SoftwareCatalogue|ownership|UUID" +docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -E "Stackiq|ownership|UUID" ``` ## Implementation Notes diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index ee66d8e8..9c1d0eae 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -8,7 +8,7 @@ The Software Catalog app provides a REST API for configuration management and pr All API endpoints are relative to the Nextcloud base URL: ``` -https://your-nextcloud-domain/index.php/apps/softwarecatalog/api/ +https://your-nextcloud-domain/index.php/apps/stackiq/api/ ``` ## Authentication @@ -93,7 +93,7 @@ Loads configuration from register-specific JSON files. ## Service Classes API -### SoftwareCatalogueService +### StackiqService #### processContactgegevens() @@ -114,7 +114,7 @@ public function processContactgegevens(object $contactgegevensObject): bool **Usage:** ```php -$service = \OC::$server->get(SoftwareCatalogueService::class); +$service = \OC::$server->get(StackiqService::class); $result = $service->processContactgegevens($contactgegevensObject); ``` @@ -172,7 +172,7 @@ public function getUserManager(string $username): ?string **Usage:** ```php -$service = \OC::$server->get(SoftwareCatalogueService::class); +$service = \OC::$server->get(StackiqService::class); $manager = $service->getUserManager('john.doe'); ``` @@ -320,10 +320,10 @@ try { ### Programmatic User Creation ```php -use OCA\SoftwareCatalog\Service\SoftwareCatalogueService; +use OCA\Stackiq\Service\StackiqService; // Get the service -$service = \OC::$server->get(SoftwareCatalogueService::class); +$service = \OC::$server->get(StackiqService::class); // Create contactgegevens object data $contactData = [ @@ -352,9 +352,9 @@ try { ### Check User Manager ```php -use OCA\SoftwareCatalog\Service\SoftwareCatalogueService; +use OCA\Stackiq\Service\StackiqService; -$service = \OC::$server->get(SoftwareCatalogueService::class); +$service = \OC::$server->get(StackiqService::class); $username = 'john.doe'; $manager = $service->getUserManager($username); @@ -457,7 +457,7 @@ Cache is automatically invalidated on: ```php // Unit test example public function testProcessContactgegevens() { - $service = new SoftwareCatalogueService(/* dependencies */); + $service = new StackiqService(/* dependencies */); $contactObject = $this->createMockContactObject(); $result = $service->processContactgegevens($contactObject); diff --git a/docs/API_TESTING.md b/docs/API_TESTING.md index 5d4a9e20..3d09e1c3 100644 --- a/docs/API_TESTING.md +++ b/docs/API_TESTING.md @@ -1,7 +1,7 @@ -# API Testing Guide for SoftwareCatalog Integration +# API Testing Guide for Stackiq Integration **Date:** July 24, 2025 -**App:** SoftwareCatalog +**App:** Stackiq **Purpose:** Repeatable local API testing for organization synchronization ## 🚀 Recommended Testing Tools @@ -44,11 +44,11 @@ npm install -g newman-reporter-cli ## 📁 Project Structure ``` -softwarecatalog/ +stackiq/ ├── tests/ │ ├── api/ │ │ ├── postman/ -│ │ │ ├── SoftwareCatalog_API_Tests.postman_collection.json +│ │ │ ├── Stackiq_API_Tests.postman_collection.json │ │ │ ├── Local_Environment.postman_environment.json │ │ │ └── Docker_Environment.postman_environment.json │ │ ├── scripts/ @@ -67,7 +67,7 @@ softwarecatalog/ ### Collection Structure ``` -SoftwareCatalog API Tests/ +Stackiq API Tests/ ├── Setup/ │ ├── Check Configuration │ └── Verify Services @@ -113,16 +113,16 @@ SoftwareCatalog API Tests/ ### Basic Test Execution ```bash # Run all tests -newman run tests/api/postman/SoftwareCatalog_API_Tests.postman_collection.json \ +newman run tests/api/postman/Stackiq_API_Tests.postman_collection.json \ -e tests/api/postman/Local_Environment.postman_environment.json # Run specific folder -newman run tests/api/postman/SoftwareCatalog_API_Tests.postman_collection.json \ +newman run tests/api/postman/Stackiq_API_Tests.postman_collection.json \ -e tests/api/postman/Local_Environment.postman_environment.json \ --folder "Anonymous Registration" # Run with detailed reporting -newman run tests/api/postman/SoftwareCatalog_API_Tests.postman_collection.json \ +newman run tests/api/postman/Stackiq_API_Tests.postman_collection.json \ -e tests/api/postman/Local_Environment.postman_environment.json \ --reporters cli,htmlextra \ --reporter-htmlextra-export tests/api/results/newman-reports/ @@ -131,11 +131,11 @@ newman run tests/api/postman/SoftwareCatalog_API_Tests.postman_collection.json \ ### Test with Different Environments ```bash # Local development -newman run tests/api/postman/SoftwareCatalog_API_Tests.postman_collection.json \ +newman run tests/api/postman/Stackiq_API_Tests.postman_collection.json \ -e tests/api/postman/Local_Environment.postman_environment.json # Docker environment -newman run tests/api/postman/SoftwareCatalog_API_Tests.postman_collection.json \ +newman run tests/api/postman/Stackiq_API_Tests.postman_collection.json \ -e tests/api/postman/Docker_Environment.postman_environment.json ``` @@ -148,7 +148,7 @@ newman run tests/api/postman/SoftwareCatalog_API_Tests.postman_collection.json \ set -e -echo "🚀 Starting SoftwareCatalog API Tests..." +echo "🚀 Starting Stackiq API Tests..." # Configuration BASE_URL="http://localhost" @@ -461,11 +461,11 @@ curl -u 'admin:admin' \ ### Newman HTML Report ```bash # Generate detailed HTML report -newman run tests/api/postman/SoftwareCatalog_API_Tests.postman_collection.json \ +newman run tests/api/postman/Stackiq_API_Tests.postman_collection.json \ -e tests/api/postman/Local_Environment.postman_environment.json \ --reporters htmlextra \ --reporter-htmlextra-export tests/api/results/newman-reports/ \ - --reporter-htmlextra-title "SoftwareCatalog API Test Report" + --reporter-htmlextra-title "Stackiq API Test Report" ``` ### Shell Script Logging @@ -503,7 +503,7 @@ jobs: - name: Run API Tests run: | - newman run tests/api/postman/SoftwareCatalog_API_Tests.postman_collection.json \ + newman run tests/api/postman/Stackiq_API_Tests.postman_collection.json \ -e tests/api/postman/Docker_Environment.postman_environment.json \ --reporters cli,htmlextra \ --reporter-htmlextra-export tests/api/results/newman-reports/ @@ -537,13 +537,13 @@ curl -u 'admin:admin' 'http://localhost/index.php/apps/openregister/api/objects/ #### 3. Schema Configuration Issues ```bash # Check configuration -docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get softwarecatalog voorzieningen_organisatie_schema +docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get stackiq voorzieningen_organisatie_schema ``` ### Debug Mode ```bash # Run with verbose output -newman run tests/api/postman/SoftwareCatalog_API_Tests.postman_collection.json \ +newman run tests/api/postman/Stackiq_API_Tests.postman_collection.json \ -e tests/api/postman/Local_Environment.postman_environment.json \ --verbose @@ -605,4 +605,4 @@ scenarios: - [curl Documentation](https://curl.se/docs/) - [jq Documentation](https://stedolan.github.io/jq/manual/) -This comprehensive API testing setup provides repeatable, automated testing for all SoftwareCatalog integration scenarios, from basic CRUD operations to complex anonymous user registration flows. \ No newline at end of file +This comprehensive API testing setup provides repeatable, automated testing for all Stackiq integration scenarios, from basic CRUD operations to complex anonymous user registration flows. \ No newline at end of file diff --git a/docs/ARCHIMATE_QUICK_TEST.md b/docs/ARCHIMATE_QUICK_TEST.md index 7e60047b..b9c46405 100644 --- a/docs/ARCHIMATE_QUICK_TEST.md +++ b/docs/ARCHIMATE_QUICK_TEST.md @@ -3,7 +3,7 @@ ## 🚀 One-Line Full Test ```bash -cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/compare_archimate.php +cd /home/rubenlinde/nextcloud-docker-dev && docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/compare_archimate.php ``` This command will: @@ -17,22 +17,22 @@ This command will: ### Import Test ```bash -docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" -H "Content-Type: application/json" -u admin:admin -d '{"file_path": "/var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml"}' +docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import" -H "Content-Type: application/json" -u admin:admin -d '{"file_path": "/var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml"}' ``` ### Export Test ```bash -docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/export" -H "Content-Type: application/json" -u admin:admin -d '{}' > /tmp/test_export.xml +docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/export" -H "Content-Type: application/json" -u admin:admin -d '{}' > /tmp/test_export.xml ``` ### Database Inspection ```bash -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/debug_db.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/debug_db.php ``` ### Clear Status ```bash -docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import/cancel" -u admin:admin +docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import/cancel" -u admin:admin ``` ## 🎯 Expected Results @@ -67,12 +67,12 @@ Folders compared: X ## 🔧 Troubleshooting ### If Import Fails -1. Check file exists: `docker-compose exec nextcloud ls -la /var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml` -2. Clear status: `docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/softwarecatalog/api/archimate/import/cancel" -u admin:admin` +1. Check file exists: `docker-compose exec nextcloud ls -la /var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml` +2. Clear status: `docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/stackiq/api/archimate/import/cancel" -u admin:admin` 3. Check logs: `docker-compose exec nextcloud tail -n 50 /var/www/html/data/nextcloud.log` ### If Export is Empty -1. Verify import worked: `docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/debug_db.php` +1. Verify import worked: `docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/debug_db.php` 2. Check object counts in database 3. Re-run import if needed diff --git a/docs/ARCHIMATE_TESTING_GUIDE.md b/docs/ARCHIMATE_TESTING_GUIDE.md index fc7ab3c1..f14ed40f 100644 --- a/docs/ARCHIMATE_TESTING_GUIDE.md +++ b/docs/ARCHIMATE_TESTING_GUIDE.md @@ -1,11 +1,11 @@ # ArchiMate Import/Export Testing Guide -This guide provides comprehensive instructions for testing the ArchiMate import/export functionality in the SoftwareCatalog application, including full round-trip testing to ensure data integrity. +This guide provides comprehensive instructions for testing the ArchiMate import/export functionality in the Stackiq application, including full round-trip testing to ensure data integrity. ## Prerequisites - Docker Compose setup with Nextcloud container running -- SoftwareCatalog and OpenRegister apps enabled +- Stackiq and OpenRegister apps enabled - Admin credentials (default: admin:admin) - Sample ArchiMate XML file (GEMMA_release.xml is included) @@ -17,10 +17,10 @@ This guide provides comprehensive instructions for testing the ArchiMate import/ # Import the sample GEMMA file cd /home/rubenlinde/nextcloud-docker-dev docker-compose exec nextcloud curl -X POST \ - "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" \ + "http://localhost/index.php/apps/stackiq/api/archimate/import" \ -H "Content-Type: application/json" \ -u admin:admin \ - -d '{"file_path": "/var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml"}' + -d '{"file_path": "/var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml"}' ``` Expected response includes statistics like: @@ -42,7 +42,7 @@ Expected response includes statistics like: ```bash # Export the imported data docker-compose exec nextcloud curl -X POST \ - "http://localhost/index.php/apps/softwarecatalog/api/archimate/export" \ + "http://localhost/index.php/apps/stackiq/api/archimate/export" \ -H "Content-Type: application/json" \ -u admin:admin \ -d '{}' > /tmp/exported_archimate.xml @@ -56,7 +56,7 @@ The application includes a comprehensive comparison script that automatically te ```bash # Run the automated comparison -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/compare_archimate.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/compare_archimate.php ``` This script will: @@ -72,12 +72,12 @@ This script will: ```bash # Clear any existing import status docker-compose exec nextcloud curl -X POST \ - "http://localhost/index.php/apps/softwarecatalog/api/archimate/import/cancel" \ + "http://localhost/index.php/apps/stackiq/api/archimate/import/cancel" \ -u admin:admin # Check that the system is ready docker-compose exec nextcloud curl -X GET \ - "http://localhost/index.php/apps/softwarecatalog/api/settings/status" \ + "http://localhost/index.php/apps/stackiq/api/settings/status" \ -u admin:admin ``` @@ -86,10 +86,10 @@ docker-compose exec nextcloud curl -X GET \ ```bash # Import the original GEMMA file docker-compose exec nextcloud curl -X POST \ - "http://localhost/index.php/apps/softwarecatalog/api/archimate/import" \ + "http://localhost/index.php/apps/stackiq/api/archimate/import" \ -H "Content-Type: application/json" \ -u admin:admin \ - -d '{"file_path": "/var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml"}' + -d '{"file_path": "/var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml"}' ``` #### Step 3: Export Imported Data @@ -97,13 +97,13 @@ docker-compose exec nextcloud curl -X POST \ ```bash # Export the data to a new file docker-compose exec nextcloud curl -X POST \ - "http://localhost/index.php/apps/softwarecatalog/api/archimate/export" \ + "http://localhost/index.php/apps/stackiq/api/archimate/export" \ -H "Content-Type: application/json" \ -u admin:admin \ -d '{}' > /tmp/round_trip_export.xml # Check the export file size (should be similar to original) -docker-compose exec nextcloud ls -lh /var/www/html/apps-extra/softwarecatalog/lib/Settings/GEMMA_release.xml +docker-compose exec nextcloud ls -lh /var/www/html/apps-extra/stackiq/lib/Settings/GEMMA_release.xml docker-compose exec nextcloud ls -lh /tmp/round_trip_export.xml ``` @@ -111,7 +111,7 @@ docker-compose exec nextcloud ls -lh /tmp/round_trip_export.xml ```bash # Run the detailed comparison -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/compare_archimate.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/compare_archimate.php # For manual inspection, check specific sections docker-compose exec nextcloud head -n 50 /tmp/round_trip_export.xml @@ -124,7 +124,7 @@ docker-compose exec nextcloud head -n 50 /tmp/round_trip_export.xml Use the included debug script to inspect what's stored in the database: ```bash -docker-compose exec nextcloud php /var/www/html/apps-extra/softwarecatalog/debug_db.php +docker-compose exec nextcloud php /var/www/html/apps-extra/stackiq/debug_db.php ``` This will show: @@ -159,7 +159,7 @@ foreach ($query->fetchAll() as $row) { ```bash # Check a specific element docker-compose exec nextcloud curl -X GET \ - "http://localhost/index.php/apps/softwarecatalog/api/archimate/export" \ + "http://localhost/index.php/apps/stackiq/api/archimate/export" \ -u admin:admin | grep -A 10 "id-009fa62f25844aa3a87d252bf2b6bb0c" ``` @@ -173,7 +173,7 @@ Expected output should include: ```bash # Check relationships structure docker-compose exec nextcloud curl -X GET \ - "http://localhost/index.php/apps/softwarecatalog/api/archimate/export" \ + "http://localhost/index.php/apps/stackiq/api/archimate/export" \ -u admin:admin | grep -A 5 -B 2 'schemaValidate("/path/to/archimate.xsd")) { ```bash # Count elements in original vs export echo "Original elements:" -docker-compose exec nextcloud grep -c 'get(ContactpersoonService::class); @@ -197,7 +197,7 @@ The method provides detailed logging at different levels: ## Related Files -- `softwarecatalog/lib/Service/ContactpersoonService.php` - Main service implementation -- `softwarecatalog/lib/Controller/ContactpersonenController.php` - API controller -- `softwarecatalog/appinfo/routes.php` - API route definition -- `softwarecatalog/lib/Examples/ContactpersoonServiceExample.php` - Usage examples +- `stackiq/lib/Service/ContactpersoonService.php` - Main service implementation +- `stackiq/lib/Controller/ContactpersonenController.php` - API controller +- `stackiq/appinfo/routes.php` - API route definition +- `stackiq/lib/Examples/ContactpersoonServiceExample.php` - Usage examples diff --git a/docs/FRONTEND_INTEGRATION.md b/docs/FRONTEND_INTEGRATION.md index 86830eec..72a1adee 100644 --- a/docs/FRONTEND_INTEGRATION.md +++ b/docs/FRONTEND_INTEGRATION.md @@ -13,7 +13,7 @@ Added a new method `fetchContactPersonsWithUserDetails()` to the Pinia store: ```javascript async fetchContactPersonsWithUserDetails(organizationUuid) { try { - const url = generateUrl(`/apps/softwarecatalog/api/contactpersonen/organisation/${organizationUuid}/with-user-details`) + const url = generateUrl(`/apps/stackiq/api/contactpersonen/organisation/${organizationUuid}/with-user-details`) const response = await fetch(url, { method: 'GET', @@ -201,7 +201,7 @@ To test the integration: ## Related Files -- `softwarecatalog/src/store/modules/organisatie.js` - Store with new API method -- `softwarecatalog/src/components/ContactpersonenList.vue` - Component with enhanced data loading -- `softwarecatalog/lib/Service/ContactpersoonService.php` - Backend service -- `softwarecatalog/lib/Controller/ContactpersonenController.php` - API controller +- `stackiq/src/store/modules/organisatie.js` - Store with new API method +- `stackiq/src/components/ContactpersonenList.vue` - Component with enhanced data loading +- `stackiq/lib/Service/ContactpersoonService.php` - Backend service +- `stackiq/lib/Controller/ContactpersonenController.php` - API controller diff --git a/docs/GROUP_MANAGEMENT.md b/docs/GROUP_MANAGEMENT.md index 0780663e..8d6a8c74 100644 --- a/docs/GROUP_MANAGEMENT.md +++ b/docs/GROUP_MANAGEMENT.md @@ -118,7 +118,7 @@ Every user automatically gets a manager assigned: ### Manager Storage Manager relationships are stored in Nextcloud user preferences: -- **App**: 'softwarecatalog' +- **App**: 'stackiq' - **Key**: 'manager' - **Value**: Manager's username @@ -195,7 +195,7 @@ All operations are logged with appropriate detail levels: ### Adding New Role-Based Groups -To add new role-based groups, update the '_defaultGroups' array in SoftwareCatalogueService: +To add new role-based groups, update the '_defaultGroups' array in StackiqueService: ```php private array $_defaultGroups = [ diff --git a/docs/MODULE_COMPLIANCE_SUBSCRIBER.md b/docs/MODULE_COMPLIANCE_SUBSCRIBER.md index 2b912a79..96bd2fb2 100644 --- a/docs/MODULE_COMPLIANCE_SUBSCRIBER.md +++ b/docs/MODULE_COMPLIANCE_SUBSCRIBER.md @@ -2,7 +2,7 @@ ## Overzicht -De Module Compliance Subscriber is een nieuwe functionaliteit in de SoftwareCatalog app die automatisch de `standaarden` property van module objecten synchroniseert op basis van gekoppelde compliance objecten. +De Module Compliance Subscriber is een nieuwe functionaliteit in de Stackiq app die automatisch de `standaarden` property van module objecten synchroniseert op basis van gekoppelde compliance objecten. ## Functionaliteit @@ -55,8 +55,8 @@ $context->registerEventListener(ObjectCreatedEvent::class, ModuleComplianceSubsc $context->registerEventListener(ObjectUpdatedEvent::class, ModuleComplianceSubscriber::class); // Service registratie -$context->registerService(\OCA\SoftwareCatalog\Service\ModuleComplianceService::class, function ($container) { - return new \OCA\SoftwareCatalog\Service\ModuleComplianceService( +$context->registerService(\OCA\Stackiq\Service\ModuleComplianceService::class, function ($container) { + return new \OCA\Stackiq\Service\ModuleComplianceService( $container, $container->get(SettingsService::class), $container->get('Psr\Log\LoggerInterface') @@ -99,10 +99,10 @@ Voor het testen van de functionaliteit is een test script beschikbaar: ```bash # Eenvoudige service test -docker exec -u 33 master-nextcloud-1 php /var/www/html/apps-extra/softwarecatalog/test_module_compliance_simple.php +docker exec -u 33 master-nextcloud-1 php /var/www/html/apps-extra/stackiq/test_module_compliance_simple.php # Volledige functionaliteit test (vereist geconfigureerde schemas) -docker exec -u 33 master-nextcloud-1 php /var/www/html/apps-extra/softwarecatalog/test_module_compliance.php +docker exec -u 33 master-nextcloud-1 php /var/www/html/apps-extra/stackiq/test_module_compliance.php ``` ## Logging diff --git a/docs/ORGANIZATION_SYNC_USECASES.md b/docs/ORGANIZATION_SYNC_USECASES.md index 1dad567b..7911f9c0 100644 --- a/docs/ORGANIZATION_SYNC_USECASES.md +++ b/docs/ORGANIZATION_SYNC_USECASES.md @@ -1,7 +1,7 @@ # Organization Synchronization Use Cases and Testing **Date:** July 24, 2025 -**App:** SoftwareCatalog +**App:** Stackiq **Feature:** Organization Synchronization with OpenRegister ## 🚨 QUICK REFERENCE FOR NEW CONVERSATION @@ -31,10 +31,10 @@ docker-compose exec -u 33 nextcloud php /var/www/html/occ user:list docker-compose exec -u 33 nextcloud php /var/www/html/occ user:info {username} # Log monitoring -docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -i "softwarecatalog" +docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -i "stackiq" # Configuration -docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get softwarecatalog voorzieningen_organisatie_schema +docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get stackiq voorzieningen_organisatie_schema ``` ### Architecture Summary @@ -51,13 +51,13 @@ docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get softwar ## Overview -This document outlines the use cases and testing scenarios for the new organization synchronization functionality in the Software Catalog app. The feature enables automatic synchronization between SoftwareCatalog organizations and OpenRegister, along with user status management based on organization status. +This document outlines the use cases and testing scenarios for the new organization synchronization functionality in the Software Catalog app. The feature enables automatic synchronization between Stackiq organizations and OpenRegister, along with user status management based on organization status. ## Use Cases ### 1. Organization Creation Synchronization -**Scenario:** A new organization is created in SoftwareCatalog +**Scenario:** A new organization is created in Stackiq **Expected Behavior:** - Organization data is automatically synced to OpenRegister @@ -66,7 +66,7 @@ This document outlines the use cases and testing scenarios for the new organizat - Contactpersonen are processed and users are created (inactive initially) **Test Steps:** -1. Create a new organization in SoftwareCatalog with status `actief` +1. Create a new organization in Stackiq with status `actief` 2. Verify organization appears in OpenRegister with `active: true` 3. Verify organization UUID is identical in both systems 4. Create contactpersonen for the organization @@ -109,7 +109,7 @@ This document outlines the use cases and testing scenarios for the new organizat ### 4. Organization Deletion -**Scenario:** Organization is deleted from SoftwareCatalog +**Scenario:** Organization is deleted from Stackiq **Expected Behavior:** - All users in the organization are deactivated @@ -134,7 +134,7 @@ This document outlines the use cases and testing scenarios for the new organizat - Organization membership is properly established **Test Steps:** -1. Create organization in SoftwareCatalog +1. Create organization in Stackiq 2. Create contactpersoon for the organization 3. Verify user account is created 4. Verify username is added to organization's users list @@ -164,7 +164,7 @@ This document outlines the use cases and testing scenarios for the new organizat **Scenario:** Organizations and contactpersonen use UUIDs across systems **Expected Behavior:** -- Organization UUIDs are identical in SoftwareCatalog and OpenRegister +- Organization UUIDs are identical in Stackiq and OpenRegister - Contactpersoon UUIDs are preserved during processing - UUID-based lookups work correctly in both systems @@ -175,9 +175,9 @@ This document outlines the use cases and testing scenarios for the new organizat 4. Verify UUID is preserved during user creation 5. Test UUID-based lookups in both systems -### 8. SoftwareCatalog-Specific User Status Management +### 8. Stackiq-Specific User Status Management -**Scenario:** Organization status changes affect only SoftwareCatalog-specific users (from contactpersoon objects), while admin group users remain protected. +**Scenario:** Organization status changes affect only Stackiq-specific users (from contactpersoon objects), while admin group users remain protected. **Expected Behavior:** - When organization becomes `inactief`: Only contactpersoon users are deactivated @@ -207,7 +207,7 @@ This document outlines the use cases and testing scenarios for the new organizat - User can be activated/deactivated with organization status changes **Test Steps:** -1. Create organization in SoftwareCatalog +1. Create organization in Stackiq 2. Create contact person with organization reference 3. Verify user account is created 4. Verify username is added to organization's users list @@ -222,7 +222,7 @@ This document outlines the use cases and testing scenarios for the new organizat - Admin group users are always added to organizations - Admin group users are never deactivated when organization becomes inactive - Admin group users remain active regardless of organization status -- Only SoftwareCatalog-specific users (contactpersonen) are affected by status changes +- Only Stackiq-specific users (contactpersonen) are affected by status changes **Test Steps:** 1. Create organization with admin users present @@ -350,7 +350,7 @@ This document outlines the use cases and testing scenarios for the new organizat ### Test Environment Setup **Prerequisites:** -- SoftwareCatalog app enabled +- Stackiq app enabled - OpenRegister app enabled - Proper schema and register configuration - Test organization and contactpersoon schemas configured @@ -400,7 +400,7 @@ This document outlines the use cases and testing scenarios for the new organizat // Test organization creation and OpenRegister sync public function testOrganizationCreationSync(): void { - // 1. Create organization in SoftwareCatalog + // 1. Create organization in Stackiq $organizationData = $this->createTestOrganization(); $organization = $this->createOrganization($organizationData); @@ -540,19 +540,19 @@ public function testOrganizationMembership(): void ### Debug Commands ```bash # Check organization sync status -docker exec -u 33 master-nextcloud-1 php /var/www/html/occ softwarecatalog:debug:organization-sync +docker exec -u 33 master-nextcloud-1 php /var/www/html/occ stackiq:debug:organization-sync # Check user status for organization -docker exec -u 33 master-nextcloud-1 php /var/www/html/occ softwarecatalog:debug:user-status --organization=UUID +docker exec -u 33 master-nextcloud-1 php /var/www/html/occ stackiq:debug:user-status --organization=UUID # Check organization membership -docker exec -u 33 master-nextcloud-1 php /var/www/html/occ softwarecatalog:debug:organization-membership --organization=UUID +docker exec -u 33 master-nextcloud-1 php /var/www/html/occ stackiq:debug:organization-membership --organization=UUID ``` ## Future Enhancements ### Planned Features -- Bidirectional sync (OpenRegister → SoftwareCatalog) +- Bidirectional sync (OpenRegister → Stackiq) - Bulk organization operations - Advanced status mapping - Custom field synchronization @@ -567,6 +567,6 @@ docker exec -u 33 master-nextcloud-1 php /var/www/html/occ softwarecatalog:debug ## Conclusion -The organization synchronization feature provides seamless integration between SoftwareCatalog and OpenRegister, ensuring data consistency and proper user management. The comprehensive testing framework ensures reliable operation across various scenarios and edge cases. +The organization synchronization feature provides seamless integration between Stackiq and OpenRegister, ensuring data consistency and proper user management. The comprehensive testing framework ensures reliable operation across various scenarios and edge cases. -For questions or issues, refer to the SoftwareCatalog documentation or contact the development team. \ No newline at end of file +For questions or issues, refer to the Stackiq documentation or contact the development team. \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 17a9a7f9..31676902 100644 --- a/docs/README.md +++ b/docs/README.md @@ -52,7 +52,7 @@ Welcome to the Software Catalog app documentation. This app provides comprehensi ## System Architecture ``` -OpenRegister Events → SoftwareCatalogEventListener → SoftwareCatalogueService +OpenRegister Events → StackiqEventListener → StackiqService ↓ User Creation ← Group Assignment ← Organization Processing ← Manager Assignment ↓ ↓ ↓ ↓ diff --git a/docs/TESTING_ORGANIZATION_SYNC.md b/docs/TESTING_ORGANIZATION_SYNC.md index 0ff78ea9..2bd7fca4 100644 --- a/docs/TESTING_ORGANIZATION_SYNC.md +++ b/docs/TESTING_ORGANIZATION_SYNC.md @@ -1,7 +1,7 @@ # Organization Synchronization Testing Guide **Date:** July 24, 2025 -**App:** SoftwareCatalog +**App:** Stackiq **Feature:** Organization Synchronization with OpenRegister ## 🚨 ESSENTIAL INFORMATION FOR NEW CONVERSATION @@ -15,16 +15,16 @@ ### Critical API Endpoints -#### SoftwareCatalog Sync API (NEW) +#### Stackiq Sync API (NEW) ```bash # Manual sync trigger -curl -u 'admin:admin' -X POST 'http://localhost/index.php/apps/softwarecatalog/api/settings/sync' +curl -u 'admin:admin' -X POST 'http://localhost/index.php/apps/stackiq/api/settings/sync' # Get sync status -curl -u 'admin:admin' 'http://localhost/index.php/apps/softwarecatalog/api/settings/sync-status' +curl -u 'admin:admin' 'http://localhost/index.php/apps/stackiq/api/settings/sync-status' # Check sync configuration -curl -u 'admin:admin' 'http://localhost/index.php/apps/softwarecatalog/api/settings' +curl -u 'admin:admin' 'http://localhost/index.php/apps/stackiq/api/settings' ``` #### OpenRegister API (Authenticated) @@ -94,10 +94,10 @@ docker-compose exec -u 33 nextcloud php /var/www/html/occ user:info {username} | #### Configuration ```bash -# Check SoftwareCatalog configuration -docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get softwarecatalog voorzieningen_organisatie_schema -docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get softwarecatalog voorzieningen_contactpersoon_schema -docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get softwarecatalog voorzieningen_register +# Check Stackiq configuration +docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get stackiq voorzieningen_organisatie_schema +docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get stackiq voorzieningen_contactpersoon_schema +docker-compose exec -u 33 nextcloud php /var/www/html/occ config:app:get stackiq voorzieningen_register ``` ### Log Reading @@ -110,8 +110,8 @@ docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log # Filter for OrganizationSyncService events (NEW) docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -i "organizationsyncservice" -# Filter for SoftwareCatalog events -docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -i "softwarecatalog" +# Filter for Stackiq events +docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -i "stackiq" # Filter for specific organization UUID docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep "{UUID}" @@ -166,7 +166,7 @@ docker-compose exec nextcloud grep -i "organizationcontactsyncjob" /var/www/html #### 1. Cron-Based Synchronization (PRIORITY) - **Status**: ✅ Code implemented, 🔄 Testing needed - **Background Job**: `OrganizationContactSyncJob` runs every 5 minutes -- **Manual Trigger**: `POST /apps/softwarecatalog/api/settings/sync` +- **Manual Trigger**: `POST /apps/stackiq/api/settings/sync` - **Expected**: Organizations synchronized, entities created, users managed - **Logging**: Comprehensive step-by-step logging in `OrganizationSyncService` @@ -184,7 +184,7 @@ docker-compose exec nextcloud grep -i "organizationcontactsyncjob" /var/www/html #### 3. User Status Management - **Status**: ✅ Implemented, 🔄 Testing needed - **Test**: Change organization `beoordeling` from `actief` to `inactief` -- **Expected**: Only SoftwareCatalog users deactivated, admin users protected +- **Expected**: Only Stackiq users deactivated, admin users protected ### Known Issues and Solutions @@ -206,7 +206,7 @@ docker-compose exec nextcloud grep -i "organizationcontactsyncjob" /var/www/html #### 4. UUID Format Mismatch (CURRENT ISSUE) - **Problem**: Organization object UUIDs use standard format (with hyphens: `ddaf232b-acbc-4396-946d-f80ccc2d3eb1`) but OpenRegister expects 32-character hex strings (without hyphens: `ddaf232bacbc4396946df80ccc2d3eb1`) - **Error**: `"Field 'uuid' doesn't have a default value"` when creating organization entities -- **Root Cause**: OpenConnector tries to create organization entity immediately, before SoftwareCatalog event listener can process it +- **Root Cause**: OpenConnector tries to create organization entity immediately, before Stackiq event listener can process it - **Solution**: ✅ Implemented UUID format conversion in `createOrganisationInOpenRegister()` method - **Status**: 🔄 **PARTIALLY FIXED** - Works for authenticated API calls, but OpenConnector still has the issue - **Next Steps**: Need to fix OpenConnector's `ObjectService::createFromArray()` method to handle UUID format conversion @@ -244,17 +244,17 @@ docker-compose exec nextcloud curl -s -u 'admin:admin' -H 'Content-Type: applica }' ``` -This will trigger the same SoftwareCatalog event listener and test our UUID fix without the OpenConnector issue. +This will trigger the same Stackiq event listener and test our UUID fix without the OpenConnector issue. ### Debugging Commands #### Synchronization Testing (NEW) ```bash # Test manual synchronization -curl -u 'admin:admin' -X POST 'http://localhost/index.php/apps/softwarecatalog/api/settings/sync' +curl -u 'admin:admin' -X POST 'http://localhost/index.php/apps/stackiq/api/settings/sync' # Check sync status -curl -u 'admin:admin' 'http://localhost/index.php/apps/softwarecatalog/api/settings/sync-status' +curl -u 'admin:admin' 'http://localhost/index.php/apps/stackiq/api/settings/sync-status' # Monitor synchronization logs docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -i "organizationsyncservice" @@ -279,8 +279,8 @@ docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -E ``` ### File Locations -- **Main Service**: `/var/www/html/apps-extra/softwarecatalog/lib/Service/SoftwareCatalogueService.php` -- **Event Listener**: `/var/www/html/apps-extra/softwarecatalog/lib/EventListener/SoftwareCatalogEventListener.php` +- **Main Service**: `/var/www/html/apps-extra/stackiq/lib/Service/StackiqueService.php` +- **Event Listener**: `/var/www/html/apps-extra/stackiq/lib/EventListener/StackiqEventListener.php` - **Logs**: `/var/www/html/data/nextcloud.log` - **Configuration**: `/var/www/html/config/config.php` @@ -300,7 +300,7 @@ This document provides comprehensive testing scenarios for the organization sync ### Configuration Verification Before testing, verify the Software Catalog configuration: ```bash -docker exec -it -u 33 master-nextcloud-1 bash -c "curl -u 'admin:admin' 'http://localhost/index.php/apps/softwarecatalog/api/settings'" +docker exec -it -u 33 master-nextcloud-1 bash -c "curl -u 'admin:admin' 'http://localhost/index.php/apps/stackiq/api/settings'" ``` Expected configuration: @@ -318,7 +318,7 @@ Expected configuration: #### 0.1 Manual Synchronization Test 1. Trigger manual synchronization: ```bash -curl -u 'admin:admin' -X POST 'http://localhost/index.php/apps/softwarecatalog/api/settings/sync' +curl -u 'admin:admin' -X POST 'http://localhost/index.php/apps/stackiq/api/settings/sync' ``` 2. Monitor the logs for detailed execution steps: @@ -328,7 +328,7 @@ docker-compose exec nextcloud tail -f /var/www/html/data/nextcloud.log | grep -i 3. Check sync status: ```bash -curl -u 'admin:admin' 'http://localhost/index.php/apps/softwarecatalog/api/settings/sync-status' +curl -u 'admin:admin' 'http://localhost/index.php/apps/stackiq/api/settings/sync-status' ``` **Expected Log Output**: @@ -493,9 +493,9 @@ docker exec -it -u 33 master-nextcloud-1 bash -c "curl -u 'admin:admin' 'http:// - All users in organization follow organization status - User accounts properly activated/deactivated in Nextcloud -### 7. SoftwareCatalog-Specific User Activation/Deactivation Test +### 7. Stackiq-Specific User Activation/Deactivation Test -**Objective**: Verify that when an organization status changes, only SoftwareCatalog-specific users (from contactpersoon objects) are activated/deactivated, while admin group users remain unaffected. +**Objective**: Verify that when an organization status changes, only Stackiq-specific users (from contactpersoon objects) are activated/deactivated, while admin group users remain unaffected. **Test Steps**: @@ -529,7 +529,7 @@ docker exec -u 33 master-nextcloud-1 php /var/www/html/occ user:list | grep -E " docker exec -it -u 33 master-nextcloud-1 bash -c "curl -u 'admin:admin' -H 'Content-Type: application/json' -X PUT -d '{\"naam\":\"Test Org with Users\",\"website\":\"https://test-users.org\",\"type\":\"Leverancier\",\"beoordeling\":\"inactief\"}' 'http://localhost/index.php/apps/openregister/api/objects/6/35/{ORGANIZATION_ID}'" ``` -5. Verify SoftwareCatalog users are deactivated but admin users remain active: +5. Verify Stackiq users are deactivated but admin users remain active: ```bash # Check user status after deactivation docker exec -u 33 master-nextcloud-1 php /var/www/html/occ user:list | grep -E "john.doe|jane.smith|admin" @@ -539,7 +539,7 @@ docker exec -u 33 master-nextcloud-1 php /var/www/html/occ user:info admin ``` **Expected Results**: -- SoftwareCatalog users (john.doe, jane.smith) are deactivated +- Stackiq users (john.doe, jane.smith) are deactivated - Admin group users remain active and unaffected - Organization status shows as "inactief" @@ -549,7 +549,7 @@ docker exec -u 33 master-nextcloud-1 php /var/www/html/occ user:info admin docker exec -it -u 33 master-nextcloud-1 bash -c "curl -u 'admin:admin' -H 'Content-Type: application/json' -X PUT -d '{\"naam\":\"Test Org with Users\",\"website\":\"https://test-users.org\",\"type\":\"Leverancier\",\"beoordeling\":\"actief\"}' 'http://localhost/index.php/apps/openregister/api/objects/6/35/{ORGANIZATION_ID}'" ``` -2. Verify SoftwareCatalog users are reactivated: +2. Verify Stackiq users are reactivated: ```bash # Check user status after reactivation docker exec -u 33 master-nextcloud-1 php /var/www/html/occ user:list | grep -E "john.doe|jane.smith|admin" @@ -561,7 +561,7 @@ docker exec -u 33 master-nextcloud-1 php /var/www/html/occ user:info admin ``` **Expected Results**: -- SoftwareCatalog users (john.doe, jane.smith) are reactivated +- Stackiq users (john.doe, jane.smith) are reactivated - Admin group users remain active - Organization status shows as "actief" @@ -637,7 +637,7 @@ docker exec -u 33 master-nextcloud-1 php /var/www/html/occ user:info regular.use **Expected Results**: - Admin users (admin, testadmin) remain active -- Regular SoftwareCatalog user (regular.user) is deactivated +- Regular Stackiq user (regular.user) is deactivated - Admin group users are completely protected from organization status changes ### 10. Bulk User Management Test @@ -936,8 +936,8 @@ docker-compose exec nextcloud curl -X POST "http://localhost/index.php/apps/open **Current Status**: - ✅ **Endpoint accessible**: The OpenConnector endpoint is working and accessible from within the Docker container - ❌ **UUID Issue**: Currently getting "Field 'uuid' doesn't have a default value" error when creating organization entities -- 🔄 **Fix in progress**: UUID format conversion implemented in SoftwareCatalog service (standard UUID with hyphens → 32-char hex string) -- ⚠️ **OpenConnector Issue**: The error occurs in OpenConnector before SoftwareCatalog event listener can process it +- 🔄 **Fix in progress**: UUID format conversion implemented in Stackiq service (standard UUID with hyphens → 32-char hex string) +- ⚠️ **OpenConnector Issue**: The error occurs in OpenConnector before Stackiq event listener can process it **Expected Results** (once UUID issue is resolved): - Organization object created successfully via OpenConnector @@ -1010,17 +1010,17 @@ docker exec -u 33 master-nextcloud-1 php /var/www/html/occ user:info anonymous.c ### Check Event Logs ```bash -docker logs master-nextcloud-1 --since 10m | grep -E "\[SoftwareCatalog\]|\[ObjectCreatedEvent\]|\[ObjectUpdatedEvent\]|\[ObjectDeletedEvent\]" +docker logs master-nextcloud-1 --since 10m | grep -E "\[Stackiq\]|\[ObjectCreatedEvent\]|\[ObjectUpdatedEvent\]|\[ObjectDeletedEvent\]" ``` ### Check App Status ```bash -docker exec -u 33 master-nextcloud-1 php /var/www/html/occ app:list | grep softwarecatalog +docker exec -u 33 master-nextcloud-1 php /var/www/html/occ app:list | grep stackiq ``` ### Enable App if Needed ```bash -docker exec -u 33 master-nextcloud-1 php /var/www/html/occ app:enable softwarecatalog +docker exec -u 33 master-nextcloud-1 php /var/www/html/occ app:enable stackiq ``` ### Check Nextcloud Logs diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 266bc4df..86748cdf 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -179,7 +179,7 @@ SoftwareCatalog: Set user manager: john.smith → jane.doe To add new role-based groups: -1. **Code Modification**: Update SoftwareCatalogueService +1. **Code Modification**: Update StackiqService 2. **Documentation**: Document new role meanings 3. **Testing**: Verify assignment works correctly diff --git a/docs/View_API.md b/docs/View_API.md index 584301ce..7e00d381 100644 --- a/docs/View_API.md +++ b/docs/View_API.md @@ -283,15 +283,15 @@ The API is designed to support future enhancements: ```bash # Test basic functionality -curl -X GET "http://localhost/index.php/apps/softwarecatalog/api/views" \\ +curl -X GET "http://localhost/index.php/apps/stackiq/api/views" \\ -H "Content-Type: application/json" # Test with enrichment -curl -X GET "http://localhost/index.php/apps/softwarecatalog/api/views?include_products=true" \\ +curl -X GET "http://localhost/index.php/apps/stackiq/api/views?include_products=true" \\ -H "Content-Type: application/json" # Test specific view -curl -X GET "http://localhost/index.php/apps/softwarecatalog/api/views/view-lv01" \\ +curl -X GET "http://localhost/index.php/apps/stackiq/api/views/view-lv01" \\ -H "Content-Type: application/json" ``` diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index c9951d1c..d0fec761 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -1,12 +1,12 @@ // @ts-check /** - * SoftwareCatalog documentation site. + * Stackiq documentation site. * * Built on @conduction/docusaurus-preset for brand defaults (tokens, * theme swizzles for Navbar / Footer, four-locale i18n scaffolding, * KvK / BTW copyright). Site-specific overrides — locales, sidebar - * path, mermaid theme, custom prism themes, softwarecatalog-only + * path, mermaid theme, custom prism themes, stackiq-only * navbar items — are passed through createConfig() opts. */ @@ -19,16 +19,16 @@ const { createConfig, baseFooterLinks } = require('@conduction/docusaurus-preset const BRAND_THEME = require.resolve('@conduction/docusaurus-preset/theme'); const config = createConfig({ - title: 'SoftwareCatalog', + title: 'Stackiq', tagline: 'IT-asset management on Nextcloud. Software inventory, licenses, contracts, dependencies. One register, every install.', url: 'https://softwarecatalog.conduction.nl', baseUrl: '/', organizationName: 'ConductionNL', - projectName: 'softwarecatalog', + projectName: 'stackiq', /* The brand preset's default i18n block (nl/en/de/fr) is replaced - wholesale here. SoftwareCatalog docs ship with NL + EN translation + wholesale here. Stackiq docs ship with NL + EN translation surfaces; keep both. */ i18n: { defaultLocale: 'en', @@ -39,10 +39,10 @@ const config = createConfig({ }, }, - /* The softwarecatalog docs source lives at the repo root of `docs/` + /* The stackiq docs source lives at the repo root of `docs/` rather than under a `docs/` subfolder, so we override the preset's default `presets:` block to point `docs.path` at './' and disable - the blog plugin. customCss carries softwarecatalog-specific CSS + the blog plugin. customCss carries stackiq-specific CSS only — brand tokens and the theme swizzles are auto-loaded by the brand theme entry in `themes:` below. */ presets: [ @@ -57,7 +57,7 @@ const config = createConfig({ plus the standard node_modules bucket. */ exclude: ['**/node_modules/**', 'src/**'], sidebarPath: require.resolve('./sidebars.js'), - editUrl: 'https://codeberg.org/Conduction/softwarecatalog/src/branch/main/docs/', + editUrl: 'https://codeberg.org/Conduction/stackiq/src/branch/main/docs/', }, blog: false, theme: { @@ -70,7 +70,7 @@ const config = createConfig({ themes: [BRAND_THEME, '@docusaurus/theme-mermaid'], /* Brand navbar provides locale dropdown + GitHub by default; we - replace items[] with softwarecatalog's own (Documentation sidebar + replace items[] with stackiq's own (Documentation sidebar link, GitHub link, locale dropdown). */ navbar: { items: [ @@ -81,7 +81,7 @@ const config = createConfig({ label: 'Documentation', }, { - href: 'https://codeberg.org/Conduction/softwarecatalog', + href: 'https://codeberg.org/Conduction/stackiq', label: 'GitHub', position: 'right', }, @@ -107,7 +107,7 @@ const config = createConfig({ /* themeConfig is shallow-merged into the preset's defaults (colorMode + navbar + footer). prism + mermaid land alongside. */ themeConfig: { - image: 'img/og-softwarecatalog.png', + image: 'img/og-stackiq.png', prism: { theme: require('prism-react-renderer/themes/github'), darkTheme: require('prism-react-renderer/themes/dracula'), diff --git a/docs/features/README.md b/docs/features/README.md index c6a7fc74..82747cae 100644 --- a/docs/features/README.md +++ b/docs/features/README.md @@ -50,7 +50,7 @@ The **Applications** (`/modules`) and **Services** (`/diensten`) index pages off **Key service:** `lib/Service/FacetService.php` **Controller:** `lib/Controller/FacetController.php` -**Endpoint:** `GET /apps/softwarecatalog/api/facets/{schema}` (`schema`: `module` or `dienst`) +**Endpoint:** `GET /apps/stackiq/api/facets/{schema}` (`schema`: `module` or `dienst`) ## Module Tracking @@ -120,8 +120,8 @@ Software Catalogus can synchronise catalogue data across organisations via the o This enables a federated, collaborative catalogue across Dutch municipalities without a central authority. -**Key service:** `lib/Service/SoftwareCatalogueService.php` -**Subservices:** `lib/Service/SoftwareCatalogue/` (dedicated handlers per sync scenario) +**Key service:** `lib/Service/StackiqService.php` +**Subservices:** `lib/Service/Stackiq/` (dedicated handlers per sync scenario) ## Automatic User Provisioning diff --git a/docs/features/catalog-ratings.md b/docs/features/catalog-ratings.md index 1a9d05af..a3c194e1 100644 --- a/docs/features/catalog-ratings.md +++ b/docs/features/catalog-ratings.md @@ -10,7 +10,7 @@ Turns the previously dormant `beoordeeling` (review) schema into a working, and closes the authorization hole it shipped with (world-readable, no create/update/delete rules, no attributable author). See [VNG Softwarecatalogus issue #49](https://github.com/VNG-Realisatie/Softwarecatalogus/issues/49) -and softwarecatalog#375. +and stackiq#375. Specification: [`openspec/specs/catalog-ratings/spec.md`](../../openspec/specs/catalog-ratings/spec.md). @@ -34,7 +34,7 @@ session, bound server-side by `ReviewService`; anything the client sends for `auteur` is discarded. ``` -POST /apps/softwarecatalog/api/reviews +POST /apps/stackiq/api/reviews { "review": {"naam": "Solid intake flow", "waardering": 9, "beschrijvingLang": "..."}, "subjectType": "module", "subjectId": "" } ``` @@ -92,7 +92,7 @@ approved reviews shows a null average / zero count rather than an error. - **No `DienstDetail` page yet.** The submit/aggregate backend is subject-type-agnostic (`module` or `dienst`), and `beoordeeling` already - supports a `diensten` relation, but the softwarecatalog manifest has no + supports a `diensten` relation, but the stackiq manifest has no `/diensten/:id` detail route today (`Diensten` is a `type: custom` faceted index with no per-row detail page) — that is a pre-existing gap unrelated to the authorization fix this change makes. Filed as a follow-up to wire diff --git a/docs/features/eol-feed-integration.md b/docs/features/eol-feed-integration.md index e47be549..e1443e45 100644 --- a/docs/features/eol-feed-integration.md +++ b/docs/features/eol-feed-integration.md @@ -16,7 +16,7 @@ what populates the field they already read. Specification: [`openspec/specs/eol-feed-integration/spec.md`](../../openspec/specs/eol-feed-integration/spec.md). -## Architecture: softwarecatalog never calls endoflife.date +## Architecture: stackiq never calls endoflife.date All fetching of endoflife.date data happens in the sibling **openconnector** `endoflife-date-source` change — a Source + Synchronization + Mapping that @@ -33,7 +33,7 @@ openconnector (sibling repo, optional) endoflife-date-source: fetches endoflife.date → eolProduct/eolCycle objects │ read-only, via ObjectService — NO HTTP here ▼ -softwarecatalog (this feature) +stackiq (this feature) module.eolProductSlug ──┐ (mapping config, per product) │ EolSyncJob (scheduled) ─► EolSyncService ─► EolMatcherService @@ -120,7 +120,7 @@ Reason codes surfaced in the settings status panel: - **Register slug** / **eolProduct schema slug** / **eolCycle schema slug** — pre-filled with the names the openconnector `endoflife-date-source` change provisions (`openconnector` / `eolProduct` / `eolCycle`). Editable - without a code change, since openconnector and softwarecatalog are + without a code change, since openconnector and stackiq are separate release trains and the provisioned names could differ. - **Sync interval (minutes)** — how often the scheduled job re-runs (minimum enforced: 5 minutes). @@ -131,10 +131,10 @@ Reason codes surfaced in the settings status panel: ## API ``` -GET /apps/softwarecatalog/api/eol-sync/config — current configuration -POST /apps/softwarecatalog/api/eol-sync/config — update configuration -POST /apps/softwarecatalog/api/eol-sync/trigger — run a sync now, returns status -GET /apps/softwarecatalog/api/eol-sync/status — last-recorded status +GET /apps/stackiq/api/eol-sync/config — current configuration +POST /apps/stackiq/api/eol-sync/config — update configuration +POST /apps/stackiq/api/eol-sync/trigger — run a sync now, returns status +GET /apps/stackiq/api/eol-sync/status — last-recorded status ``` All four endpoints require Nextcloud admin-group authorization (the default diff --git a/docs/features/multi-org-membership.md b/docs/features/multi-org-membership.md index 069c3eab..0bb3456c 100644 --- a/docs/features/multi-org-membership.md +++ b/docs/features/multi-org-membership.md @@ -18,7 +18,7 @@ gemeentelijke herindeling. See Specification: [`openspec/specs/multi-org-membership/spec.md`](../../openspec/specs/multi-org-membership/spec.md). Everything in this feature is built on OpenRegister's own, already-shipped -`OrganisationService`/`OrganisationController` — SoftwareCatalog does not +`OrganisationService`/`OrganisationController` — Stackiq does not store a separate membership record anywhere. ## Switching your active organisation @@ -29,7 +29,7 @@ organisation's name. Opening it lists every organisation the user belongs to; picking a different one: 1. Calls OpenRegister's own `POST /apps/openregister/api/organisations/{uuid}/set-active` - directly — SoftwareCatalog does not proxy this call. + directly — Stackiq does not proxy this call. 2. OpenRegister verifies, server-side, that the caller is actually a member of that organisation (`Organisation::hasUser()`) before changing anything. A switch to an organisation the user does not belong to is @@ -58,11 +58,11 @@ header switcher, opening a dialog for their currently-active organisation: flow, and never creates a Nextcloud account. - **Revoke access** — remove a member from the list. -Both actions are authorised server-side by a new, SoftwareCatalog-specific +Both actions are authorised server-side by a new, Stackiq-specific check (`OrganisationMembersController::authorizeBeheerder()`) that OpenRegister's own membership endpoints don't perform (OpenRegister's `join`/`leave` only recognise a Nextcloud admin or the organisation's single `owner` field as -allowed to manage another user's membership — SoftwareCatalog's `beheerder` +allowed to manage another user's membership — Stackiq's `beheerder` role is a separate, broader concept). The check requires **both**: 1. The caller is authenticated and in the global `beheerder` Nextcloud group. @@ -77,10 +77,10 @@ A beheerder of one organisation cannot grant or revoke access to a role. ``` -POST /apps/softwarecatalog/api/organisations/{uuid}/members +POST /apps/stackiq/api/organisations/{uuid}/members { "userId": "j.devries" } -DELETE /apps/softwarecatalog/api/organisations/{uuid}/members/{userId} +DELETE /apps/stackiq/api/organisations/{uuid}/members/{userId} ``` ## What this does not do @@ -93,7 +93,7 @@ DELETE /apps/softwarecatalog/api/organisations/{uuid}/members/{userId} govern what each role may read within that organisation are unchanged (`vendor-visibility-rbac`). - **No cross-organisation data merge.** That is a different capability - ([organisation merge](organisation-merge.md), softwarecatalog#370). + ([organisation merge](organisation-merge.md), stackiq#370). ## Screenshots diff --git a/docs/features/organisation-merge.md b/docs/features/organisation-merge.md index 0469ea1d..ee42db62 100644 --- a/docs/features/organisation-merge.md +++ b/docs/features/organisation-merge.md @@ -37,7 +37,7 @@ every object above and returns a count per relation type, without writing anything: ``` -POST /apps/softwarecatalog/api/organisaties/{sourceUuid}/merge/dry-run +POST /apps/stackiq/api/organisaties/{sourceUuid}/merge/dry-run { "targetUuid": "" } ``` @@ -59,7 +59,7 @@ UUID) and execute will refuse it too, with the same validation. ## Executing a merge ``` -POST /apps/softwarecatalog/api/organisaties/{sourceUuid}/merge +POST /apps/stackiq/api/organisaties/{sourceUuid}/merge { "targetUuid": "", "confirm": true } ``` diff --git a/docs/features/portfolio-rationalization-time.md b/docs/features/portfolio-rationalization-time.md index 7875f167..243f2c85 100644 --- a/docs/features/portfolio-rationalization-time.md +++ b/docs/features/portfolio-rationalization-time.md @@ -58,7 +58,7 @@ never fork into two competing sources of the same fact. ## The portfolio rationalization report -`GET /apps/softwarecatalog/api/portfolio-report?organisation={uuid}` +`GET /apps/stackiq/api/portfolio-report?organisation={uuid}` Returns a bounded, organisation-scoped aggregate: @@ -139,7 +139,7 @@ The controller resolves and checks the caller's organisation access ### CSV export -`GET /apps/softwarecatalog/api/portfolio-report?organisation={uuid}&format=csv` +`GET /apps/stackiq/api/portfolio-report?organisation={uuid}&format=csv` The **same** bounded, RBAC-scoped row set as the JSON report, serialised as CSV (one row per gebruik: organisation, module, TIME classification, diff --git a/docs/features/sbom-import.md b/docs/features/sbom-import.md index 017c79d6..3ece825c 100644 --- a/docs/features/sbom-import.md +++ b/docs/features/sbom-import.md @@ -21,7 +21,7 @@ Choose a format (CycloneDX or SPDX, both JSON) and a file, then **Import SBOM**: ``` -POST /apps/softwarecatalog/api/moduleversies/{moduleVersieUuid}/sbom +POST /apps/stackiq/api/moduleversies/{moduleVersieUuid}/sbom multipart/form-data: sbomFile=, format=cyclonedx-json|spdx-json ``` diff --git a/docs/features/suite-wizard.md b/docs/features/suite-wizard.md index f97afba4..ad74ff90 100644 --- a/docs/features/suite-wizard.md +++ b/docs/features/suite-wizard.md @@ -10,7 +10,7 @@ product made up of one or more existing applications, e.g. "Centric Leefomgeving" — and attach its member applications in one guided pass. This replaces the retired incumbent "product" concept per [VNG Softwarecatalogus issue #242](https://github.com/VNG-Realisatie/Softwarecatalogus/issues/242) -and softwarecatalog#372. +and stackiq#372. Specification: [`openspec/specs/suite-wizard/spec.md`](../../openspec/specs/suite-wizard/spec.md). diff --git a/docs/gmail-configuration-manual.md b/docs/gmail-configuration-manual.md index b13c3bf4..0f1b6b29 100644 --- a/docs/gmail-configuration-manual.md +++ b/docs/gmail-configuration-manual.md @@ -68,7 +68,7 @@ Fill in the following settings: | Setting | Value | Example | |---------|--------|---------| -| **Sender Email** | `your-email@gmail.com` | `softwarecatalog@yourorg.com` | +| **Sender Email** | `your-email@gmail.com` | `stackiq@yourorg.com` | | **Sender Name** | `Your Organization Name` | `Software Catalog Team` | ### Configure Email Types (Optional) diff --git a/docs/i18n/nl/docusaurus-theme-classic/footer.json b/docs/i18n/nl/docusaurus-theme-classic/footer.json index 1056ef3f..1c75a88c 100644 --- a/docs/i18n/nl/docusaurus-theme-classic/footer.json +++ b/docs/i18n/nl/docusaurus-theme-classic/footer.json @@ -13,7 +13,7 @@ }, "link.item.label.GitHub": { "message": "GitHub", - "description": "The label of footer link with label=GitHub linking to https://codeberg.org/Conduction/softwarecatalog" + "description": "The label of footer link with label=GitHub linking to https://codeberg.org/Conduction/stackiq" }, "copyright": { "message": "Copyright © 2026 for Open Webconcept by Conduction B.V.", diff --git a/docs/package-lock.json b/docs/package-lock.json index 39a3f6bd..46eb5d68 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -1,11 +1,11 @@ { - "name": "softwarecatalog-docs", + "name": "stackiq-docs", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "softwarecatalog-docs", + "name": "stackiq-docs", "version": "0.0.0", "dependencies": { "@conduction/docusaurus-preset": "^3.26.0", diff --git a/docs/package.json b/docs/package.json index 6bb31b55..26af351e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,5 +1,5 @@ { - "name": "softwarecatalog-docs", + "name": "stackiq-docs", "version": "0.0.0", "private": true, "scripts": { diff --git a/docs/security/vendor-visibility-rbac.md b/docs/security/vendor-visibility-rbac.md index ff9e3a38..21dee488 100644 --- a/docs/security/vendor-visibility-rbac.md +++ b/docs/security/vendor-visibility-rbac.md @@ -6,7 +6,7 @@ or `contract` OpenRegister object, enumerated with its authorization posture and the test(s) that cover it, per [REQ-007](../../openspec/specs/vendor-visibility-rbac/spec.md#requirement-every-route-touching-gebruik-koppeling-or-contract-objects-must-have-a-documented-tested-authorization-posture-req-007). -**Updated by `schema-rbac-hardening`** (softwarecatalog #379, #390, #378): +**Updated by `schema-rbac-hardening`** (stackiq #379, #390, #378): closed the two follow-up gaps this audit originally flagged below — the `gebruik`/`koppeling`/`organisatie` schema-level RBAC gap and the `AanbodController::getAanbod()` implicit-guard gap — and extended the @@ -43,14 +43,14 @@ controllers named in the proposal's discovery phase. | `PUT /api/publication/{objectType}/{uuid}/publish`, `DELETE /api/publication/{objectType}/{uuid}/depublish` | `PublicationController::publish` / `depublish` | dienst/module/koppeling/organisatie | Write path only (sets `publicatiedatum`/`depublicatiedatum`); not a bulk read. Already has a per-object ownership guard (admin, or aanbod-beheerder whose org owns the entry). Out of scope per proposal ("Changes to the open-data publishing mechanism ... out of scope"). | Pre-existing | | `GET /api/contracts/approval/config` | `ContractApprovalController::config` | — | Authenticated-only; returns a boolean config flag, no contract data. Not a contract read. | N/A | | `POST /api/contracts/{contractUuid}/approval/submit`, `POST /api/contracts/{contractUuid}/approval/renewal` | `ContractApprovalController::submit` / `submitRenewal` | contract | Write (delegation) path only — no contract data returned. Per-object ownership guard confirmed present (`authorizeContract()` → `ContractApprovalService::authorizeSubmit()`, `_organisation`-matched). Confirmed correct, unaffected by this change. | Pre-existing `ContractApprovalControllerTest` | -| *(no app-local route)* | Contract object reads (list/detail) | contract | Contract CRUD runs entirely through the OpenRegister object store (ADR-022, `contract-administration`) via the manifest renderer — there is no SoftwareCatalog controller for contract reads. Visibility is governed exclusively by the OpenRegister `contract` schema's own `authorization.read` RBAC rule. **Fixed (REQ-006):** removed the blanket `"public"` grant and the unscoped `"aanbod-beheerder"` grant; `aanbod-beheerder` is now match-scoped to `_organisation == $organisation` in `lib/Settings/softwarecatalogus_register.json`. **Extended (REQ-006, `schema-rbac-hardening`, #390):** every remaining bare role (`functioneel-beheerder`, `gebruik-beheerder`, `vng-raadpleger`, `software-catalog-users`, `organisatie-beheerder`, `organisaties-beheerder`, `gebruik-raadpleger`) is now match-scoped the same way; `ambtenaar` and `software-catalog-admins` (the app's super-user group) remain deliberately unscoped — see `design.md` Decision 4. | `ContractRbacTest` | -| *(no app-local route)* | Koppeling object reads (list/detail) | koppeling | No SoftwareCatalog controller reads koppeling through the generic OpenRegister object API. Visibility is governed exclusively by the `koppeling` schema's `authorization.read` rule. **Fixed (REQ-008, `schema-rbac-hardening`, #379):** the bare unscoped `gebruik-beheerder` grant is now match-scoped to `_organisation == $organisation`. Every app-local `koppeling` read (see `AangebodenGebruikController`/`AanbodController` rows above) already bypasses schema RBAC with `_rbac:false` and does its own scoping, so this was not a live leak through those routes — but was live-exploitable via any generic OpenRegister object-API read outside this app. | `SchemaRbacTest` | -| *(no app-local route)* | Organisatie object reads (list/detail) | organisatie | No SoftwareCatalog controller reads organisatie through the generic OpenRegister object API. Visibility is governed exclusively by the `organisatie` schema's `authorization.read` rule (plus its three pre-existing `public` match rules for active organisaties, unaffected by this change). **Fixed (REQ-008, `schema-rbac-hardening`, #379):** the bare unscoped `gebruik-beheerder` grant is now match-scoped to `_organisation == $organisation`; only non-public/inactive organisatie records were affected. | `SchemaRbacTest` | +| *(no app-local route)* | Contract object reads (list/detail) | contract | Contract CRUD runs entirely through the OpenRegister object store (ADR-022, `contract-administration`) via the manifest renderer — there is no Stackiq controller for contract reads. Visibility is governed exclusively by the OpenRegister `contract` schema's own `authorization.read` RBAC rule. **Fixed (REQ-006):** removed the blanket `"public"` grant and the unscoped `"aanbod-beheerder"` grant; `aanbod-beheerder` is now match-scoped to `_organisation == $organisation` in `lib/Settings/softwarecatalogus_register.json`. **Extended (REQ-006, `schema-rbac-hardening`, #390):** every remaining bare role (`functioneel-beheerder`, `gebruik-beheerder`, `vng-raadpleger`, `software-catalog-users`, `organisatie-beheerder`, `organisaties-beheerder`, `gebruik-raadpleger`) is now match-scoped the same way; `ambtenaar` and `software-catalog-admins` (the app's super-user group) remain deliberately unscoped — see `design.md` Decision 4. | `ContractRbacTest` | +| *(no app-local route)* | Koppeling object reads (list/detail) | koppeling | No Stackiq controller reads koppeling through the generic OpenRegister object API. Visibility is governed exclusively by the `koppeling` schema's `authorization.read` rule. **Fixed (REQ-008, `schema-rbac-hardening`, #379):** the bare unscoped `gebruik-beheerder` grant is now match-scoped to `_organisation == $organisation`. Every app-local `koppeling` read (see `AangebodenGebruikController`/`AanbodController` rows above) already bypasses schema RBAC with `_rbac:false` and does its own scoping, so this was not a live leak through those routes — but was live-exploitable via any generic OpenRegister object-API read outside this app. | `SchemaRbacTest` | +| *(no app-local route)* | Organisatie object reads (list/detail) | organisatie | No Stackiq controller reads organisatie through the generic OpenRegister object API. Visibility is governed exclusively by the `organisatie` schema's `authorization.read` rule (plus its three pre-existing `public` match rules for active organisaties, unaffected by this change). **Fixed (REQ-008, `schema-rbac-hardening`, #379):** the bare unscoped `gebruik-beheerder` grant is now match-scoped to `_organisation == $organisation`; only non-public/inactive organisatie records were affected. | `SchemaRbacTest` | ## Findings summary - **Fixed by `vendor-visibility-rbac`:** `GET /api/gebruik` (gebruik-beheerder cross-org leak, discovery.md finding 2), `GET /api/aangeboden-gebruik/afnemer` (implicit-only auth), OpenRegister `contract` schema RBAC read rule (blanket `public` + unscoped `aanbod-beheerder`). -- **Fixed by `schema-rbac-hardening`** (softwarecatalog #379, #390, #378): `koppeling` and `organisatie` schema RBAC (`gebruik-beheerder` unscoped grant), the remaining bare roles on `contract` schema RBAC beyond `aanbod-beheerder`, and `AanbodController::getAanbod()`'s implicit-only auth guard. See REQ-008/REQ-009 and the "Schema-level RBAC layer" section below. +- **Fixed by `schema-rbac-hardening`** (stackiq #379, #390, #378): `koppeling` and `organisatie` schema RBAC (`gebruik-beheerder` unscoped grant), the remaining bare roles on `contract` schema RBAC beyond `aanbod-beheerder`, and `AanbodController::getAanbod()`'s implicit-only auth guard. See REQ-008/REQ-009 and the "Schema-level RBAC layer" section below. - **Confirmed correct, now regression-tested:** `GET /api/koppelingen-gebruik/{uuid}`, `GET /api/aangeboden-gebruik/{afnemer,deelnemers}`, `GET /api/gebruik/deelnemer`. - **Confirmed correct, unaffected (already had their own field-scoping or role guard):** `GET /api/views` (gebruik/deelnames-gebruik enrichment), `GET/POST /api/aangeboden-gebruik/ambtenaar*`, all `PublicationController`/`ContractApprovalController`/`AangebodenGebruikController` write paths. - **Documented accepted residual (not fixed, not silently dropped):** the `gebruik.deelnemers` array-membership sharing case — see below. @@ -101,7 +101,7 @@ implemented ad hoc in an app-level register config. ## Deployment caveat: silent no-op until #391 lands `schema-rbac-hardening`'s register-JSON fixes have **no runtime effect on -any already-installed instance** until softwarecatalog #391 +any already-installed instance** until stackiq #391 (`register-import-reliability`) lands — the repair-step importer currently no-ops when a register/schema it has already imported once is edited again. This change must ship after, or together with, #391, and the fix diff --git a/docs/src/pages/index.js b/docs/src/pages/index.js index 501a364b..964f5783 100644 --- a/docs/src/pages/index.js +++ b/docs/src/pages/index.js @@ -1,9 +1,9 @@ /** - * SoftwareCatalog landing page. + * Stackiq landing page. * * Composes the brand + from * @conduction/docusaurus-preset/components, mirroring the connext page - * at sites/www/src/pages/apps/softwarecatalog.mdx. + * at sites/www/src/pages/apps/stackiq.mdx. * * Written as .js (not .mdx) because the docs site has the docs plugin * pointed at `path: './'`, and an MDX file in src/pages/ trips the @@ -25,7 +25,7 @@ import { the tile-grid motif reads as "rows in a register" for both apps (catalog of items vs. catalog of widgets) and ties the two product surfaces together visually. Cited from the connext detail page at - sites/www/src/pages/apps/softwarecatalog.mdx. */ + sites/www/src/pages/apps/stackiq.mdx. */ const SOFTWARECATALOG_ICON = ( @@ -294,37 +294,37 @@ const WIDGETS = [ export default function Home() { return (
} + illustration={} />
diff --git a/docs/static/llms.txt b/docs/static/llms.txt index d7006aed..341e282c 100644 --- a/docs/static/llms.txt +++ b/docs/static/llms.txt @@ -1,8 +1,8 @@ -# SoftwareCatalog +# Stackiq -> SoftwareCatalog is an open-source IT-asset-management app for the Nextcloud workspace. +> Stackiq is an open-source IT-asset-management app for the Nextcloud workspace. -SoftwareCatalog is an open-source IT-asset-management app for the Nextcloud workspace. It keeps a central register of every application, licence, contract, and dependency the organisation runs, with renewal alerts before the auto-renewal date. Dashboard widgets surface upcoming renewals, an inventory snapshot by category, and discovery deltas showing newly added or removed apps. Built for the IT department that needs to know what runs where, without a separate asset database or second login. Released under EUPL-1.2 and maintained by Conduction since 2019. +Stackiq is an open-source IT-asset-management app for the Nextcloud workspace. It keeps a central register of every application, licence, contract, and dependency the organisation runs, with renewal alerts before the auto-renewal date. Dashboard widgets surface upcoming renewals, an inventory snapshot by category, and discovery deltas showing newly added or removed apps. Built for the IT department that needs to know what runs where, without a separate asset database or second login. Released under EUPL-1.2 and maintained by Conduction since 2019. ## Docs @@ -12,8 +12,8 @@ SoftwareCatalog is an open-source IT-asset-management app for the Nextcloud work ## Optional - [Install](https://www.conduction.nl/install): self-host on your Nextcloud instance. -- [Source code](https://codeberg.org/Conduction/softwarecatalog): repository and issue tracker. -- [App page](https://www.conduction.nl/apps/softwarecatalog): product positioning on conduction.nl. +- [Source code](https://codeberg.org/Conduction/stackiq): repository and issue tracker. +- [App page](https://www.conduction.nl/apps/stackiq): product positioning on conduction.nl. ## Contact diff --git a/eslint-suppressions.json b/eslint-suppressions.json index d8594712..855f5d7d 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -394,7 +394,7 @@ "count": 2 } }, - "src/store/plugins/softwarecatalogPlugin.js": { + "src/store/plugins/stackiqPlugin.js": { "no-console": { "count": 5 }, @@ -474,7 +474,7 @@ "count": 1 } }, - "src/views/settings/SoftwareCatalogSettings.vue": { + "src/views/settings/StackiqSettings.vue": { "jsdoc/require-param-type": { "count": 3 }, diff --git a/issues.md b/issues.md index f44b74ef..10a19085 100644 --- a/issues.md +++ b/issues.md @@ -223,7 +223,7 @@ Previously closed (2026-02-22): #185, #266, #267, #286, #294, #300, #302, #307, **Summary:** As a gebruik-beheerder, we want suppliers (aanbod-beheerder) to not see our application landscapes and connections. The RBAC model scopes data visibility per organization — the page itself may be accessible, but aanbod-beheerder should only see their own organization's data. -**RBAC Reference:** See `softwarecatalog/lib/Settings/softwarecatalogus_register.json`: +**RBAC Reference:** See `stackiq/lib/Settings/softwarecatalogus_register.json`: - `module` (applicatie) schema → `authorization.read`: `{ "group": "aanbod-beheerder", "match": { "_organisation": "$organisation" } }` — own org only - `koppeling` schema → `authorization.read`: `{ "group": "aanbod-beheerder", "match": { "_organisation": "$organisation" } }` — own org only @@ -1778,7 +1778,7 @@ Previously closed (2026-02-22): #185, #266, #267, #286, #294, #300, #302, #307, **Summary:** Contact persons of **gemeenten** (municipalities) are publicly visible but should NOT be. Note: contact persons of **leveranciers** (vendors) ARE expected to be publicly visible — only gemeente/samenwerking contact persons should be hidden. -**RBAC Reference:** See `softwarecatalog/lib/Settings/softwarecatalogus_register.json` → `contactpersoon` schema → `authorization` block. The `contactpersoon` schema does NOT have `public` read access. Leverancier contact persons are exposed via **publications** (which extend contactpersonen), not via direct public access to the contactpersoon schema. +**RBAC Reference:** See `stackiq/lib/Settings/softwarecatalogus_register.json` → `contactpersoon` schema → `authorization` block. The `contactpersoon` schema does NOT have `public` read access. Leverancier contact persons are exposed via **publications** (which extend contactpersonen), not via direct public access to the contactpersoon schema. **Acceptance Criteria:** - [x] [API] Contact persons of **leveranciers** ARE visible on public pages (this is expected/correct behavior) diff --git a/l10n/be.js b/l10n/be.js index 06f6fe51..18cdffbf 100644 --- a/l10n/be.js +++ b/l10n/be.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/bg.js b/l10n/bg.js index fd8a5bfa..d93693a1 100644 --- a/l10n/bg.js +++ b/l10n/bg.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/bs.js b/l10n/bs.js index 6d165269..9ca1053a 100644 --- a/l10n/bs.js +++ b/l10n/bs.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/ca.js b/l10n/ca.js index 9c4c9cc5..a3e7bc15 100644 --- a/l10n/ca.js +++ b/l10n/ca.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/cs.js b/l10n/cs.js index cb456d33..16de9025 100644 --- a/l10n/cs.js +++ b/l10n/cs.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/da.js b/l10n/da.js index d55f3f96..3f96efc2 100644 --- a/l10n/da.js +++ b/l10n/da.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/de.js b/l10n/de.js index 98910613..d8b6c5ae 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/el.js b/l10n/el.js index 3722bee0..2b107591 100644 --- a/l10n/el.js +++ b/l10n/el.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/en.js b/l10n/en.js index 2295bce9..2e40fbc7 100644 --- a/l10n/en.js +++ b/l10n/en.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "AMEF elements" : "AMEF elements", "AMEF standards" : "AMEF standards", diff --git a/l10n/en.json b/l10n/en.json index 3b34a715..ee3f047d 100644 --- a/l10n/en.json +++ b/l10n/en.json @@ -537,7 +537,6 @@ "Last run: {matched} matched, {skipped} skipped, at {time}.": "Last run: {matched} matched, {skipped} skipped, at {time}.", "Loading EOL sync configuration…": "Loading EOL sync configuration…", "Loading merge status": "Loading merge status", - "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Softwarecatalog never calls endoflife.date directly.": "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Softwarecatalog never calls endoflife.date directly.", "Merge organisation": "Merge organisation", "Merge organisations": "Merge organisations", "never": "never", @@ -688,6 +687,8 @@ "Could not update the {label}": "Could not update the {label}", "Add a new contact person to organisation: {name}": "Add a new contact person to organisation: {name}", "Failed to add contact person: {error}": "Failed to add contact person: {error}", - "Invalid contact person data structure": "Invalid contact person data structure" + "Invalid contact person data structure": "Invalid contact person data structure", + "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Stackiq never calls endoflife.date directly.": "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Stackiq never calls endoflife.date directly.", + "Stackiq Location URL": "Stackiq Location URL" } } diff --git a/l10n/en_US.js b/l10n/en_US.js index e160e615..6765f0ac 100644 --- a/l10n/en_US.js +++ b/l10n/en_US.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", @@ -260,7 +260,7 @@ OC.L10N.register( "Group members" : "Group members", "Merge organisations" : "Merge organisations", "End-of-life feed sync" : "End-of-life feed sync", - "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Softwarecatalog never calls endoflife.date directly." : "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Softwarecatalog never calls endoflife.date directly.", + "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Stackiq never calls endoflife.date directly." : "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Stackiq never calls endoflife.date directly.", "Loading EOL sync configuration…" : "Loading EOL sync configuration…", "Save EOL sync settings" : "Save EOL sync settings", "Sync now" : "Sync now", diff --git a/l10n/en_US.json b/l10n/en_US.json index 8fee0daa..3693bd60 100644 --- a/l10n/en_US.json +++ b/l10n/en_US.json @@ -302,7 +302,6 @@ "Group members": "Group members", "Merge organisations": "Merge organisations", "End-of-life feed sync": "End-of-life feed sync", - "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Softwarecatalog never calls endoflife.date directly.": "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Softwarecatalog never calls endoflife.date directly.", "Loading EOL sync configuration…": "Loading EOL sync configuration…", "Save EOL sync settings": "Save EOL sync settings", "Sync now": "Sync now", @@ -376,7 +375,6 @@ "Import a CycloneDX or SPDX SBOM to see this version's components, licenses and any matching known vulnerabilities.": "Import a CycloneDX or SPDX SBOM to see this version's components, licenses and any matching known vulnerabilities.", "Confirmed match": "Confirmed match", "Possible match": "Possible match", - "Name": "Name", "Version": "Version", "Package URL": "Package URL", "Licenses": "Licenses", @@ -429,15 +427,6 @@ "Could not load applications. Please try again.": "Could not load applications. Please try again.", "Applications ({count})": "Applications ({count})", "No applications attached yet.": "No applications attached yet.", - "Approve": "Approve", - "Reject": "Reject", - "Nothing to moderate": "Nothing to moderate", - "Refresh queue": "Refresh queue", - "Registration moderation": "Registration moderation", - "Review anonymous catalog registrations. Approving an entry publishes it; rejecting leaves it hidden.": "Review anonymous catalog registrations. Approving an entry publishes it; rejecting leaves it hidden.", - "Loading pending registrations…": "Loading pending registrations…", - "There are no pending registrations right now.": "There are no pending registrations right now.", - "Could not load the moderation queue": "Could not load the moderation queue", "{label} approved and published": "{label} approved and published", "{label} rejected": "{label} rejected", "{label} has no identifier": "{label} has no identifier", @@ -472,6 +461,7 @@ "Current members": "Current members", "No members yet.": "No members yet.", "Revoke access": "Revoke access", - "Close": "Close" + "Close": "Close", + "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Stackiq never calls endoflife.date directly.": "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Stackiq never calls endoflife.date directly." } } diff --git a/l10n/es.js b/l10n/es.js index ff91aaf6..8eb29407 100644 --- a/l10n/es.js +++ b/l10n/es.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/et.js b/l10n/et.js index d7e932b3..21daf809 100644 --- a/l10n/et.js +++ b/l10n/et.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/fi.js b/l10n/fi.js index 522b806d..59474e4e 100644 --- a/l10n/fi.js +++ b/l10n/fi.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/fr.js b/l10n/fr.js index da58d6b8..bef79b41 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/ga.js b/l10n/ga.js index 5336188a..9eccb9db 100644 --- a/l10n/ga.js +++ b/l10n/ga.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/hr.js b/l10n/hr.js index 7b5ab0dc..cd772827 100644 --- a/l10n/hr.js +++ b/l10n/hr.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/hu.js b/l10n/hu.js index 68d25d84..621d9d3e 100644 --- a/l10n/hu.js +++ b/l10n/hu.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/is.js b/l10n/is.js index e9d7d694..34fbd291 100644 --- a/l10n/is.js +++ b/l10n/is.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/it.js b/l10n/it.js index 81281724..868e5787 100644 --- a/l10n/it.js +++ b/l10n/it.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/lb.js b/l10n/lb.js index 29c443a6..1327853c 100644 --- a/l10n/lb.js +++ b/l10n/lb.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/lt.js b/l10n/lt.js index 9f916475..0e00640d 100644 --- a/l10n/lt.js +++ b/l10n/lt.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/lv.js b/l10n/lv.js index d257f7b4..125c8a72 100644 --- a/l10n/lv.js +++ b/l10n/lv.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/mk.js b/l10n/mk.js index 9b7c4304..585e9c48 100644 --- a/l10n/mk.js +++ b/l10n/mk.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/mt.js b/l10n/mt.js index a6dacbe0..a18df4e6 100644 --- a/l10n/mt.js +++ b/l10n/mt.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/nb.js b/l10n/nb.js index a79ec9b9..44ca59ed 100644 --- a/l10n/nb.js +++ b/l10n/nb.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/nl.js b/l10n/nl.js index 25a15fe2..068121e8 100644 --- a/l10n/nl.js +++ b/l10n/nl.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "AMEF elements" : "Amef elementen", "AMEF standards" : "Standaarden AMEF", @@ -251,7 +251,7 @@ OC.L10N.register( "Short Description" : "Korte beschrijving", "Short description" : "Korte beschrijving", "Showing {showing} of {total} {type}" : "{showing} van {total} {type} weergegeven", - "Software Catalog Location URL" : "Softwarecatalogus locatie-URL", + "Stackiq Location URL" : "Stackiq locatie-URL", "Software Catalogus needs the OpenRegister app to store and manage data. Please install OpenRegister from the app store to get started." : "De Softwarecatalogus heeft de OpenRegister-app nodig om gegevens op te slaan en te beheren. Installeer OpenRegister vanuit de app store om te beginnen.", "Start date" : "Startdatum", "Status" : "Status", @@ -380,7 +380,7 @@ OC.L10N.register( "Group members" : "Groepsleden", "Merge organisations" : "Organisaties samenvoegen", "End-of-life feed sync" : "Einde-ondersteuning-feedsynchronisatie", - "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Softwarecatalog never calls endoflife.date directly." : "Koppel catalogusproducten aan endoflife.date-productcycli die via OpenConnector zijn binnengehaald, zodat einde-ondersteuningsdata datagedreven blijft. Softwarecatalogus roept endoflife.date nooit rechtstreeks aan.", + "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Stackiq never calls endoflife.date directly." : "Koppel catalogusproducten aan endoflife.date-productcycli die via OpenConnector zijn binnengehaald, zodat einde-ondersteuningsdata datagedreven blijft. Stackiq roept endoflife.date nooit rechtstreeks aan.", "Loading EOL sync configuration…" : "EOL-synchronisatieconfiguratie laden…", "Save EOL sync settings" : "EOL-synchronisatie-instellingen opslaan", "Sync now" : "Nu synchroniseren", diff --git a/l10n/nl.json b/l10n/nl.json index d373e299..f57f73e5 100644 --- a/l10n/nl.json +++ b/l10n/nl.json @@ -303,7 +303,6 @@ "Short Description": "Korte beschrijving", "Short description": "Korte beschrijving", "Showing {showing} of {total} {type}": "{showing} van {total} {type} weergegeven", - "Software Catalog Location URL": "Softwarecatalogus locatie-URL", "Software Catalogus needs the OpenRegister app to store and manage data. Please install OpenRegister from the app store to get started.": "De Softwarecatalogus heeft de OpenRegister-app nodig om gegevens op te slaan en te beheren. Installeer OpenRegister vanuit de app store om te beginnen.", "Some compliancy records only reference a standard by name and could not be matched to a standard version. They are excluded from the matrix.": "Sommige compliancy-records verwijzen alleen via een naam naar een standaard en konden niet aan een standaardversie worden gekoppeld. Deze worden uitgesloten van de matrix.", "Standards": "Standaarden", @@ -362,12 +361,12 @@ "Add a federation peer": "Add a federation peer", "Add a peer catalog URL above to start federating.": "Add a peer catalog URL above to start federating.", "Add peer": "Add peer", - "Approve": "Approve", + "Approve": "Goedkeuren", "Blocked by SSRF guard": "Blocked by SSRF guard", "Catalog federation": "Catalog federation", "Could not add peer": "Could not add peer", "Could not load federation status": "Could not load federation status", - "Could not load the moderation queue": "Could not load the moderation queue", + "Could not load the moderation queue": "Kon de moderatiewachtrij niet laden", "Could not remove peer": "Could not remove peer", "Could not update the registration": "Could not update the registration", "Directory": "Directory", @@ -377,29 +376,29 @@ "Federation pull failed": "Federation pull failed", "Healthy": "Healthy", "Loading federation status…": "Loading federation status…", - "Loading pending registrations…": "Loading pending registrations…", + "Loading pending registrations…": "Openstaande registraties laden…", "No directory configured": "No directory configured", "No peers subscribed": "No peers subscribed", - "Nothing to moderate": "Nothing to moderate", + "Nothing to moderate": "Niets te modereren", "Peer added": "Peer added", "Peer catalog URL": "Peer catalog URL", "Peer removed": "Peer removed", "Private and loopback hosts are blocked unless explicitly allowlisted via the local_federation_hosts setting.": "Private and loopback hosts are blocked unless explicitly allowlisted via the local_federation_hosts setting.", "Pull now": "Pull now", "Pulled {count} peer(s).": "Pulled {count} peer(s).", - "Refresh queue": "Refresh queue", + "Refresh queue": "Wachtrij vernieuwen", "Refresh status": "Refresh status", "Registration approved and published": "Registration approved and published", "Registration has no identifier": "Registration has no identifier", - "Registration moderation": "Registration moderation", + "Registration moderation": "Registratiemoderatie", "Registration rejected": "Registration rejected", - "Reject": "Reject", + "Reject": "Afwijzen", "Remove peer": "Remove peer", - "Review anonymous catalog registrations. Approving an entry publishes it; rejecting leaves it hidden.": "Review anonymous catalog registrations. Approving an entry publishes it; rejecting leaves it hidden.", + "Review anonymous catalog registrations. Approving an entry publishes it; rejecting leaves it hidden.": "Beoordeel anonieme catalogusregistraties. Goedkeuren publiceert een item; afwijzen houdt het verborgen.", "Stale": "Stale", "Subscribe to peer catalogs and pull their published entries into this instance.": "Subscribe to peer catalogs and pull their published entries into this instance.", "Subscribed peers": "Subscribed peers", - "There are no pending registrations right now.": "There are no pending registrations right now.", + "There are no pending registrations right now.": "Er zijn op dit moment geen openstaande registraties.", "Publication": "Publicatie", "Publications will be soft deleted and moved to the": "Publicaties worden zacht verwijderd en verplaatst naar de", "deleted publications section": "sectie verwijderde publicaties", @@ -529,7 +528,6 @@ "Save view": "Weergave opslaan", "Approval": "Goedkeuring", "End-of-life feed sync": "Einde-ondersteuning-feedsynchronisatie", - "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Softwarecatalog never calls endoflife.date directly.": "Koppel catalogusproducten aan endoflife.date-productcycli die via OpenConnector zijn binnengehaald, zodat einde-ondersteuningsdata datagedreven blijft. Softwarecatalogus roept endoflife.date nooit rechtstreeks aan.", "Loading EOL sync configuration…": "EOL-synchronisatieconfiguratie laden…", "Save EOL sync settings": "EOL-synchronisatie-instellingen opslaan", "Sync now": "Nu synchroniseren", @@ -590,7 +588,6 @@ "TIME quadrant counts": "TIME-kwadrantaantallen", "Tolerate": "Tolereren", "Unclassified": "Ongeclassificeerd", - "Approval": "Goedkeuring", "Loading components": "Componenten laden", "Components": "Componenten", "Distinct licenses": "Unieke licenties", @@ -602,7 +599,6 @@ "Import a CycloneDX or SPDX SBOM to see this version's components, licenses and any matching known vulnerabilities.": "Importeer een CycloneDX- of SPDX-SBOM om de componenten, licenties en eventuele overeenkomende bekende kwetsbaarheden van deze versie te zien.", "Confirmed match": "Bevestigde overeenkomst", "Possible match": "Mogelijke overeenkomst", - "Name": "Naam", "Version": "Versie", "Package URL": "Package-URL", "Licenses": "Licenties", @@ -612,7 +608,6 @@ "SBOM import failed": "SBOM-import mislukt", "Imported {count} components.": "{count} componenten geïmporteerd.", "Last imported {date} from {file} ({format})": "Laatst geïmporteerd op {date} vanuit {file} ({format})", - "Approval": "Goedkeuring", "All applications": "Alle applicaties", "BBN level": "BBN-niveau", "BIO measures": "BIO-maatregelen", @@ -656,15 +651,6 @@ "Could not load applications. Please try again.": "Kon de applicaties niet laden. Probeer het opnieuw.", "Applications ({count})": "Applicaties ({count})", "No applications attached yet.": "Nog geen applicaties gekoppeld.", - "Approve": "Goedkeuren", - "Reject": "Afwijzen", - "Nothing to moderate": "Niets te modereren", - "Refresh queue": "Wachtrij vernieuwen", - "Registration moderation": "Registratiemoderatie", - "Review anonymous catalog registrations. Approving an entry publishes it; rejecting leaves it hidden.": "Beoordeel anonieme catalogusregistraties. Goedkeuren publiceert een item; afwijzen houdt het verborgen.", - "Loading pending registrations…": "Openstaande registraties laden…", - "There are no pending registrations right now.": "Er zijn op dit moment geen openstaande registraties.", - "Could not load the moderation queue": "Kon de moderatiewachtrij niet laden", "{label} approved and published": "{label} goedgekeurd en gepubliceerd", "{label} rejected": "{label} afgewezen", "{label} has no identifier": "{label} heeft geen identificatie", @@ -699,10 +685,11 @@ "Current members": "Huidige leden", "No members yet.": "Nog geen leden.", "Revoke access": "Toegang intrekken", - "Close": "Sluiten", "Vulnerability": "Kwetsbaarheid", "Connection": "Koppeling", "Assessment": "Beoordeling", - "SBOM component": "SBOM-component" + "SBOM component": "SBOM-component", + "Stackiq Location URL": "Stackiq locatie-URL", + "Match catalog products to endoflife.date product cycles ingested via OpenConnector, to keep end-of-support dates data-driven. Stackiq never calls endoflife.date directly.": "Koppel catalogusproducten aan endoflife.date-productcycli die via OpenConnector zijn binnengehaald, zodat einde-ondersteuningsdata datagedreven blijft. Stackiq roept endoflife.date nooit rechtstreeks aan." } } diff --git a/l10n/pl.js b/l10n/pl.js index 6f2b1fde..e795c225 100644 --- a/l10n/pl.js +++ b/l10n/pl.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/pt.js b/l10n/pt.js index 9fe86cef..76bc51eb 100644 --- a/l10n/pt.js +++ b/l10n/pt.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/rm.js b/l10n/rm.js index daf44b83..5373610d 100644 --- a/l10n/rm.js +++ b/l10n/rm.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/ro.js b/l10n/ro.js index bf2dad4d..a6d4cae0 100644 --- a/l10n/ro.js +++ b/l10n/ro.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/ru.js b/l10n/ru.js index 0110c294..199b74fb 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/sk.js b/l10n/sk.js index 2d9de754..e36ccfe4 100644 --- a/l10n/sk.js +++ b/l10n/sk.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/sl.js b/l10n/sl.js index 7a2df0d4..db606bea 100644 --- a/l10n/sl.js +++ b/l10n/sl.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/sq.js b/l10n/sq.js index cc5e15b5..9f596431 100644 --- a/l10n/sq.js +++ b/l10n/sq.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/sr.js b/l10n/sr.js index 264246e4..8c0808d8 100644 --- a/l10n/sr.js +++ b/l10n/sr.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/sv.js b/l10n/sv.js index 97866bb0..ccf03735 100644 --- a/l10n/sv.js +++ b/l10n/sv.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/tr.js b/l10n/tr.js index 50a64146..d6e9d555 100644 --- a/l10n/tr.js +++ b/l10n/tr.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/l10n/uk.js b/l10n/uk.js index 6d1a9913..27bcd4e1 100644 --- a/l10n/uk.js +++ b/l10n/uk.js @@ -1,5 +1,5 @@ OC.L10N.register( - "softwarecatalog", + "stackiq", { "Acquisition" : "Acquisition", "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement)." : "Applications in use for an organisation, grouped by lifecycle phase and ordered by nearest urgency (end-of-support, phase-out or planned replacement).", diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index e41a15d5..98a84ed2 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -1,24 +1,24 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\AppInfo; +namespace OCA\Stackiq\AppInfo; use OCA\Decidesk\Event\DecisionConcludedEvent; use OCA\OpenRegister\Contract\ObjectServiceInterface; @@ -26,53 +26,53 @@ use OCA\OpenRegister\Event\ObjectUpdatedEvent; use OCA\OpenRegister\Event\UserProfileUpdatedEvent; use OCA\OpenRegister\Service\OrganisationService as OpenRegisterOrganisationService; -use OCA\SoftwareCatalog\BackgroundJob\ContractStatusJob; -use OCA\SoftwareCatalog\BackgroundJob\EolSyncJob; -use OCA\SoftwareCatalog\BackgroundJob\FederationSyncJob; -use OCA\SoftwareCatalog\BackgroundJob\OrganizationContactSyncJob; -use OCA\SoftwareCatalog\Controller\ContactpersonenController; -use OCA\SoftwareCatalog\Dashboard\ConceptOrganisatiesWidget; -use OCA\SoftwareCatalog\EventListener\DecisionConcludedListener; -use OCA\SoftwareCatalog\EventListener\ModuleComplianceSubscriber; -use OCA\SoftwareCatalog\EventListener\ModuleRegistrationSubscriber; -use OCA\SoftwareCatalog\EventListener\TestEventListener; -use OCA\SoftwareCatalog\EventListener\UserProfileUpdatedEventListener; -use OCA\SoftwareCatalog\Service\ArchiMateExportService; -use OCA\SoftwareCatalog\Service\ArchiMateImportService; -use OCA\SoftwareCatalog\Service\ArchiMateService; -use OCA\SoftwareCatalog\Service\ContactpersoonService; -use OCA\SoftwareCatalog\Service\ContractApprovalService; -use OCA\SoftwareCatalog\Service\ContractStatusService; -use OCA\SoftwareCatalog\Service\EolMatcherService; -use OCA\SoftwareCatalog\Service\EolSyncService; -use OCA\SoftwareCatalog\Service\FacetService; -use OCA\SoftwareCatalog\Service\Federation\FederationConfig; -use OCA\SoftwareCatalog\Service\Federation\FederationMerger; -use OCA\SoftwareCatalog\Service\Federation\FederationService; -use OCA\SoftwareCatalog\Service\GebruikSyncService; -use OCA\SoftwareCatalog\Service\IntakeService; -use OCA\SoftwareCatalog\Service\MergeOrganisatieService; -use OCA\SoftwareCatalog\Service\ModerationService; -use OCA\SoftwareCatalog\Service\ModuleComplianceService; -use OCA\SoftwareCatalog\Service\ModuleRegistrationService; -use OCA\SoftwareCatalog\Service\ModuleVersionService; -use OCA\SoftwareCatalog\Service\OrganisatieService; -use OCA\SoftwareCatalog\Service\OrganizationSyncService; -use OCA\SoftwareCatalog\Service\ProgressTracker; -use OCA\SoftwareCatalog\Service\PublicationService; -use OCA\SoftwareCatalog\Service\ReviewAggregateService; -use OCA\SoftwareCatalog\Service\ReviewService; -use OCA\SoftwareCatalog\Service\SbomImportService; -use OCA\SoftwareCatalog\Service\SbomParserService; -use OCA\SoftwareCatalog\Service\SettingsService; -use OCA\SoftwareCatalog\Service\SoftwareCatalogContactSyncService; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\ContactPersonHandler; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\GroupHandler; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\HierarchyHandler; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\OrganizationHandler; -use OCA\SoftwareCatalog\Service\SymfonyEmailService; -use OCA\SoftwareCatalog\Service\ViewQueryBuilder; -use OCA\SoftwareCatalog\Service\ViewService; +use OCA\Stackiq\BackgroundJob\ContractStatusJob; +use OCA\Stackiq\BackgroundJob\EolSyncJob; +use OCA\Stackiq\BackgroundJob\FederationSyncJob; +use OCA\Stackiq\BackgroundJob\OrganizationContactSyncJob; +use OCA\Stackiq\Controller\ContactpersonenController; +use OCA\Stackiq\Dashboard\ConceptOrganisatiesWidget; +use OCA\Stackiq\EventListener\DecisionConcludedListener; +use OCA\Stackiq\EventListener\ModuleComplianceSubscriber; +use OCA\Stackiq\EventListener\ModuleRegistrationSubscriber; +use OCA\Stackiq\EventListener\TestEventListener; +use OCA\Stackiq\EventListener\UserProfileUpdatedEventListener; +use OCA\Stackiq\Service\ArchiMateExportService; +use OCA\Stackiq\Service\ArchiMateImportService; +use OCA\Stackiq\Service\ArchiMateService; +use OCA\Stackiq\Service\ContactpersoonService; +use OCA\Stackiq\Service\ContractApprovalService; +use OCA\Stackiq\Service\ContractStatusService; +use OCA\Stackiq\Service\EolMatcherService; +use OCA\Stackiq\Service\EolSyncService; +use OCA\Stackiq\Service\FacetService; +use OCA\Stackiq\Service\Federation\FederationConfig; +use OCA\Stackiq\Service\Federation\FederationMerger; +use OCA\Stackiq\Service\Federation\FederationService; +use OCA\Stackiq\Service\GebruikSyncService; +use OCA\Stackiq\Service\IntakeService; +use OCA\Stackiq\Service\MergeOrganisatieService; +use OCA\Stackiq\Service\ModerationService; +use OCA\Stackiq\Service\ModuleComplianceService; +use OCA\Stackiq\Service\ModuleRegistrationService; +use OCA\Stackiq\Service\ModuleVersionService; +use OCA\Stackiq\Service\OrganisatieService; +use OCA\Stackiq\Service\OrganizationSyncService; +use OCA\Stackiq\Service\ProgressTracker; +use OCA\Stackiq\Service\PublicationService; +use OCA\Stackiq\Service\ReviewAggregateService; +use OCA\Stackiq\Service\ReviewService; +use OCA\Stackiq\Service\SbomImportService; +use OCA\Stackiq\Service\SbomParserService; +use OCA\Stackiq\Service\SettingsService; +use OCA\Stackiq\Service\Stackiq\ContactPersonHandler; +use OCA\Stackiq\Service\Stackiq\GroupHandler; +use OCA\Stackiq\Service\Stackiq\HierarchyHandler; +use OCA\Stackiq\Service\Stackiq\OrganizationHandler; +use OCA\Stackiq\Service\StackiqContactSyncService; +use OCA\Stackiq\Service\SymfonyEmailService; +use OCA\Stackiq\Service\ViewQueryBuilder; +use OCA\Stackiq\Service\ViewService; use OCP\App\IAppManager; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; @@ -92,14 +92,14 @@ use Psr\Log\LoggerInterface; /** - * Main Application class for SoftwareCatalog + * Main Application class for Stackiq * * @category Application - * @package OCA\SoftwareCatalog\AppInfo + * @package OCA\Stackiq\AppInfo * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @@ -109,7 +109,7 @@ class Application extends App implements IBootstrap { /** * The application ID */ - public const APP_ID = 'softwarecatalog'; + public const APP_ID = 'stackiq'; /** * Application constructor @@ -157,7 +157,7 @@ public function register(IRegistrationContext $context): void { }//end register() /** - * Wire the four SoftwareCatalogue handler services as DI bindings. + * Wire the four Stackiq handler services as DI bindings. * * Single-responsibility helper extracted from `register()` per * `openspec/changes/method-decomposition/tasks.md` task 9.1. @@ -170,7 +170,7 @@ public function register(IRegistrationContext $context): void { */ private function registerHandlerServices(IRegistrationContext $context): void { $context->registerService( - 'OCA\SoftwareCatalog\Service\SoftwareCatalogue\OrganizationHandler', + 'OCA\Stackiq\Service\Stackiq\OrganizationHandler', function (ContainerInterface $c) { return new OrganizationHandler( _groupManager: $c->get(IGroupManager::class), @@ -183,7 +183,7 @@ function (ContainerInterface $c) { ); $context->registerService( - 'OCA\SoftwareCatalog\Service\SoftwareCatalogue\ContactPersonHandler', + 'OCA\Stackiq\Service\Stackiq\ContactPersonHandler', function (ContainerInterface $c) { return new ContactPersonHandler( _userManager: $c->get(IUserManager::class), @@ -200,7 +200,7 @@ function (ContainerInterface $c) { ); $context->registerService( - 'OCA\SoftwareCatalog\Service\SoftwareCatalogue\GroupHandler', + 'OCA\Stackiq\Service\Stackiq\GroupHandler', function (ContainerInterface $c) { return new GroupHandler( _groupManager: $c->get(IGroupManager::class), @@ -214,11 +214,11 @@ function (ContainerInterface $c) { ); $context->registerService( - 'OCA\SoftwareCatalog\Service\SoftwareCatalogue\HierarchyHandler', + 'OCA\Stackiq\Service\Stackiq\HierarchyHandler', function (ContainerInterface $c) { return new HierarchyHandler( - _organizationHandler: $c->get('OCA\SoftwareCatalog\Service\SoftwareCatalogue\OrganizationHandler'), - _contactPersonHandler: $c->get('OCA\SoftwareCatalog\Service\SoftwareCatalogue\ContactPersonHandler'), + _organizationHandler: $c->get('OCA\Stackiq\Service\Stackiq\OrganizationHandler'), + _contactPersonHandler: $c->get('OCA\Stackiq\Service\Stackiq\ContactPersonHandler'), _logger: $c->get(LoggerInterface::class), _userManager: $c->get(IUserManager::class), _groupManager: $c->get(IGroupManager::class) @@ -361,9 +361,9 @@ function ($container) { // Register the Nextcloud-Contacts bridge (identity → NC addressbook, // relationship records keyed by contactsUid; ADR-019/ADR-022). $context->registerService( - SoftwareCatalogContactSyncService::class, + StackiqContactSyncService::class, function ($container) { - return new SoftwareCatalogContactSyncService( + return new StackiqContactSyncService( contactsManager: $container->get('OCP\Contacts\IManager'), logger: $container->get('Psr\Log\LoggerInterface') ); @@ -434,7 +434,7 @@ function ($container) { ); // Register the registration/review moderation/approval-queue service - // (generalised to also moderate beoordeeling — softwarecatalog#375). + // (generalised to also moderate beoordeeling — stackiq#375). $context->registerService( ModerationService::class, function ($container) { @@ -447,7 +447,7 @@ function ($container) { ); // Register the authenticated review-submission service (catalog-ratings, - // softwarecatalog#375). Author identity comes from IUserSession, never + // stackiq#375). Author identity comes from IUserSession, never // from client input. $context->registerService( ReviewService::class, @@ -462,7 +462,7 @@ function ($container) { ); // Register the public approved-only review aggregate/read service - // (catalog-ratings, softwarecatalog#375) — split from ReviewService + // (catalog-ratings, stackiq#375) — split from ReviewService // to keep each class under the complexity budget. $context->registerService( ReviewAggregateService::class, @@ -607,7 +607,7 @@ function ($container) { return new OrganizationContactSyncJob( timeFactory: $container->get('OCP\AppFramework\Utility\ITimeFactory'), orgSyncService: $container->get(OrganizationSyncService::class), - contactSync: $container->get(SoftwareCatalogContactSyncService::class), + contactSync: $container->get(StackiqContactSyncService::class), settingsService: $container->get(SettingsService::class), appManager: $container->get(IAppManager::class), logger: $container->get(LoggerInterface::class) @@ -731,7 +731,7 @@ function ($container) { request: $container->get('OCP\IRequest'), settingsService: $container->get(SettingsService::class), contactPersonHandler: $container->get( - 'OCA\SoftwareCatalog\Service\SoftwareCatalogue\ContactPersonHandler' + 'OCA\Stackiq\Service\Stackiq\ContactPersonHandler' ), contactSvc: $container->get(ContactpersoonService::class), userManager: $container->get('OCP\IUserManager'), @@ -773,7 +773,7 @@ private function registerEventListeners(IRegistrationContext $context): void { $context->registerEventListener(UserLoggedInEvent::class, TestEventListener::class); // OpenRegister object lifecycle events are NO LONGER broadcast to - // SoftwareCatalogEventListener. + // StackiqEventListener. // // That listener's own docblock has said "DISABLED: All processing is now // handled by cron-based OrganizationSyncService to avoid race conditions" @@ -784,7 +784,7 @@ private function registerEventListeners(IRegistrationContext $context): void { // then discarded the result. // // The cost was not theoretical. Importing OpenCatalogi's configuration — - // twelve seeded objects — produced 657 SoftwareCatalog event handlings. + // twelve seeded objects — produced 657 Stackiq event handlings. // Each one resolved three services from the container and wrote six log // lines BEFORE reaching the schema check that decides the event is not // ours. `occ maintenance:repair` reached 119 of 120 steps and then sat in diff --git a/lib/BackgroundJob/ContractStatusJob.php b/lib/BackgroundJob/ContractStatusJob.php index 171d3ca9..45a8e1c9 100644 --- a/lib/BackgroundJob/ContractStatusJob.php +++ b/lib/BackgroundJob/ContractStatusJob.php @@ -12,11 +12,11 @@ * correct mechanism (tasks.md 2.1 → 2.2). * * @category BackgroundJob - * @package OCA\SoftwareCatalog\BackgroundJob + * @package OCA\Stackiq\BackgroundJob * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/contract-administration/spec.md * @@ -26,9 +26,9 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\BackgroundJob; +namespace OCA\Stackiq\BackgroundJob; -use OCA\SoftwareCatalog\Service\ContractStatusService; +use OCA\Stackiq\Service\ContractStatusService; use OCP\App\IAppManager; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\TimedJob; diff --git a/lib/BackgroundJob/EolSyncJob.php b/lib/BackgroundJob/EolSyncJob.php index 38ee9ec8..83d510c7 100644 --- a/lib/BackgroundJob/EolSyncJob.php +++ b/lib/BackgroundJob/EolSyncJob.php @@ -14,11 +14,11 @@ * sharing it. * * @category BackgroundJob - * @package OCA\SoftwareCatalog\BackgroundJob + * @package OCA\Stackiq\BackgroundJob * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/eol-feed-integration/spec.md#requirement-eol-sync-runs-on-a-schedule-with-a-manual-trigger * @@ -28,9 +28,9 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\BackgroundJob; +namespace OCA\Stackiq\BackgroundJob; -use OCA\SoftwareCatalog\Service\EolSyncService; +use OCA\Stackiq\Service\EolSyncService; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\TimedJob; use Psr\Log\LoggerInterface; @@ -58,7 +58,7 @@ public function __construct( ) { parent::__construct(time: $timeFactory); - // Floor at 300s (the shortest interval any existing SoftwareCatalog + // Floor at 300s (the shortest interval any existing Stackiq // background job runs at — OrganizationContactSyncJob) so a // mistyped admin value can never schedule a tighter loop than the // rest of the app's cron surface. diff --git a/lib/BackgroundJob/FederationSyncJob.php b/lib/BackgroundJob/FederationSyncJob.php index 265c21de..b3a701a1 100644 --- a/lib/BackgroundJob/FederationSyncJob.php +++ b/lib/BackgroundJob/FederationSyncJob.php @@ -9,11 +9,11 @@ * federation is disabled — so the job is always safe to run. * * @category BackgroundJob - * @package OCA\SoftwareCatalog\BackgroundJob + * @package OCA\Stackiq\BackgroundJob * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/federated-catalog-sync/spec.md * @@ -23,10 +23,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\BackgroundJob; +namespace OCA\Stackiq\BackgroundJob; -use OCA\SoftwareCatalog\Service\Federation\FederationConfig; -use OCA\SoftwareCatalog\Service\Federation\FederationService; +use OCA\Stackiq\Service\Federation\FederationConfig; +use OCA\Stackiq\Service\Federation\FederationService; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\TimedJob; use Psr\Log\LoggerInterface; diff --git a/lib/BackgroundJob/OrganizationContactSyncJob.php b/lib/BackgroundJob/OrganizationContactSyncJob.php index d2e14e10..575107af 100644 --- a/lib/BackgroundJob/OrganizationContactSyncJob.php +++ b/lib/BackgroundJob/OrganizationContactSyncJob.php @@ -4,24 +4,24 @@ * Organization Contact Synchronization Background Job * * This file contains the background job class for synchronizing organizations and contact persons - * between SoftwareCatalog objects and OpenRegister entities. + * between Stackiq objects and OpenRegister entities. * * @category BackgroundJob - * @package OCA\SoftwareCatalog\BackgroundJob + * @package OCA\Stackiq\BackgroundJob * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: 1.0.0 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\BackgroundJob; +namespace OCA\Stackiq\BackgroundJob; -use OCA\SoftwareCatalog\Service\OrganizationSyncService; -use OCA\SoftwareCatalog\Service\SettingsService; -use OCA\SoftwareCatalog\Service\SoftwareCatalogContactSyncService; +use OCA\Stackiq\Service\OrganizationSyncService; +use OCA\Stackiq\Service\SettingsService; +use OCA\Stackiq\Service\StackiqContactSyncService; use OCP\App\IAppManager; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\TimedJob; @@ -30,7 +30,7 @@ /** * Background job for comprehensive organization and contact person synchronization * - * This job runs every 5 minutes to ensure data consistency between SoftwareCatalog objects + * This job runs every 5 minutes to ensure data consistency between Stackiq objects * and OpenRegister entities using full sync (all organizations). All business logic is * delegated to the OrganizationSyncService. * @@ -38,11 +38,11 @@ * system-level background job that needs unrestricted access to all objects. * * @category BackgroundJob - * @package OCA\SoftwareCatalog\BackgroundJob + * @package OCA\Stackiq\BackgroundJob * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: 1.0.0 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ class OrganizationContactSyncJob extends TimedJob { @@ -58,7 +58,7 @@ class OrganizationContactSyncJob extends TimedJob { * * @param ITimeFactory $timeFactory The time factory for job scheduling * @param OrganizationSyncService $orgSyncService The sync service - * @param SoftwareCatalogContactSyncService $contactSync The Nextcloud-Contacts bridge + * @param StackiqContactSyncService $contactSync The Nextcloud-Contacts bridge * @param SettingsService $settingsService The settings service (register/schema id resolution) * @param IAppManager $appManager The Nextcloud app manager * @param LoggerInterface $logger The logger @@ -66,7 +66,7 @@ class OrganizationContactSyncJob extends TimedJob { public function __construct( ITimeFactory $timeFactory, OrganizationSyncService $orgSyncService, - private readonly SoftwareCatalogContactSyncService $contactSync, + private readonly StackiqContactSyncService $contactSync, private readonly SettingsService $settingsService, private readonly IAppManager $appManager, private readonly LoggerInterface $logger, @@ -83,7 +83,7 @@ public function __construct( * Delegates organisation/contact synchronisation to the * OrganizationSyncService, then keeps every catalog relationship record's * `contactsUid` link to the Nextcloud addressbook fresh via - * SoftwareCatalogContactSyncService. Per cross-app interface contract #2, + * StackiqContactSyncService. Per cross-app interface contract #2, * identity lives in Nextcloud Contacts — this job refreshes the link, it * does NOT mirror identity into OpenRegister. * @@ -135,7 +135,7 @@ protected function run($argument): void { * Refresh the `contactsUid` link on every contactpersoon/organisatie record. * * For each record this (re)resolves its Nextcloud Contact through - * SoftwareCatalogContactSyncService and writes back the UID only when it is + * StackiqContactSyncService and writes back the UID only when it is * missing or has changed. Never mirrors identity into OpenRegister and * never deletes a source object — a record that cannot be resolved is left * intact for a later pass. diff --git a/lib/Controller/AanbodController.php b/lib/Controller/AanbodController.php index f26a6501..9d1d8ed1 100644 --- a/lib/Controller/AanbodController.php +++ b/lib/Controller/AanbodController.php @@ -1,25 +1,25 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\Service\AanbodService; +use OCA\Stackiq\Service\AanbodService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; @@ -35,12 +35,12 @@ * (provider), and for accepting or denying these offers. * * @category Controller - * @package OCA\SoftwareCatalog\Controller + * @package OCA\Stackiq\Controller * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ class AanbodController extends Controller { /** diff --git a/lib/Controller/AangebodenGebruikController.php b/lib/Controller/AangebodenGebruikController.php index 521b0ffc..a62f8abe 100644 --- a/lib/Controller/AangebodenGebruikController.php +++ b/lib/Controller/AangebodenGebruikController.php @@ -1,26 +1,26 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\Service\AangebodenGebruikService; +use OCA\Stackiq\Service\AangebodenGebruikService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\AnonRateLimit; @@ -38,12 +38,12 @@ * (participants), and for updating the @self property of gebruiks objects. * * @category Controller - * @package OCA\SoftwareCatalog\Controller + * @package OCA\Stackiq\Controller * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @SuppressWarnings(PHPMD.ExcessiveClassLength) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) @@ -866,7 +866,7 @@ function ($key) { public function getApiDocumentation(): JSONResponse { $documentation = [ 'api_version' => '2.0.0', - 'description' => 'SoftwareCatalog AangebodenGebruik API', + 'description' => 'Stackiq AangebodenGebruik API', 'base_url' => '/api/aangeboden-gebruik', 'endpoints' => [ [ diff --git a/lib/Controller/ContactpersonenController.php b/lib/Controller/ContactpersonenController.php index 14c7e159..894356e2 100644 --- a/lib/Controller/ContactpersonenController.php +++ b/lib/Controller/ContactpersonenController.php @@ -1,18 +1,18 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * SPDX-FileCopyrightText: 2026 Conduction B.V. * SPDX-License-Identifier: EUPL-1.2 @@ -20,11 +20,13 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\Service\ContactpersoonService; -use OCA\SoftwareCatalog\Service\SettingsService; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\ContactPersonHandler; +use OCA\OpenRegister\Contract\ObjectServiceInterface; +use OCA\OpenRegister\Service\OrganisationService; +use OCA\Stackiq\Service\ContactpersoonService; +use OCA\Stackiq\Service\SettingsService; +use OCA\Stackiq\Service\Stackiq\ContactPersonHandler; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; @@ -34,8 +36,6 @@ use OCP\IUserSession; use OCP\Security\ISecureRandom; use Psr\Log\LoggerInterface; -use OCA\OpenRegister\Contract\ObjectServiceInterface; -use OCA\OpenRegister\Service\OrganisationService; /** * Controller for managing contactpersonen and their user accounts. @@ -46,12 +46,12 @@ * - Managing user group memberships * * @category Controller - * @package OCA\SoftwareCatalog\Controller + * @package OCA\Stackiq\Controller * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @SuppressWarnings(PHPMD.ExcessiveClassLength) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) diff --git a/lib/Controller/ContractApprovalController.php b/lib/Controller/ContractApprovalController.php index ed1075e4..972ba8c7 100644 --- a/lib/Controller/ContractApprovalController.php +++ b/lib/Controller/ContractApprovalController.php @@ -1,7 +1,7 @@ * @copyright 2026 Conduction B.V. @@ -32,7 +32,7 @@ * * @version GIT: * - * @link https://codeberg.org/Conduction/softwarecatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/contract-decision-delegation/spec.md * @@ -42,10 +42,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\AppInfo\Application; -use OCA\SoftwareCatalog\Service\ContractApprovalService; +use OCA\Stackiq\AppInfo\Application; +use OCA\Stackiq\Service\ContractApprovalService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\NoAdminRequired; diff --git a/lib/Controller/DashboardController.php b/lib/Controller/DashboardController.php index 8890ba43..cebdb5c2 100644 --- a/lib/Controller/DashboardController.php +++ b/lib/Controller/DashboardController.php @@ -1,18 +1,18 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; diff --git a/lib/Controller/FacetController.php b/lib/Controller/FacetController.php index 16475333..c453a6d6 100644 --- a/lib/Controller/FacetController.php +++ b/lib/Controller/FacetController.php @@ -1,16 +1,16 @@ * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * SPDX-FileCopyrightText: 2026 Conduction B.V. * SPDX-License-Identifier: EUPL-1.2 @@ -20,9 +20,9 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\Service\FacetService; +use OCA\Stackiq\Service\FacetService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -32,7 +32,7 @@ * Controller for the GEMMA-dimension facet aggregation endpoint. * * @category Controller - * @package OCA\SoftwareCatalog\Controller + * @package OCA\Stackiq\Controller * * @spec openspec/specs/gemma-faceted-search/spec.md#requirement-facet-aggregation-endpoint-returns-gemma-dimension-counts */ diff --git a/lib/Controller/FederationController.php b/lib/Controller/FederationController.php index d59aff77..e57f5b38 100644 --- a/lib/Controller/FederationController.php +++ b/lib/Controller/FederationController.php @@ -9,7 +9,7 @@ * of all configured peers. All write/read paths delegate to FederationService; * no bespoke federation logic lives here. * - * AUTH (ADR-005): every method is `#[AuthorizedAdminSetting(SoftwareCatalogAdmin::class)]` + * AUTH (ADR-005): every method is `#[AuthorizedAdminSetting(StackiqAdmin::class)]` * — Nextcloud's admin-settings middleware rejects any non-admin caller before * the controller body runs (matching the moderation controller's posture and the * service's admin-only intent), so an authenticated non-admin can never reach @@ -17,11 +17,11 @@ * OWASP A01:2021). * * @category Controller - * @package OCA\SoftwareCatalog\Controller + * @package OCA\Stackiq\Controller * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/federated-catalog-sync/spec.md * @@ -31,11 +31,11 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\AppInfo\Application; -use OCA\SoftwareCatalog\Service\Federation\FederationService; -use OCA\SoftwareCatalog\Settings\SoftwareCatalogAdmin; +use OCA\Stackiq\AppInfo\Application; +use OCA\Stackiq\Service\Federation\FederationService; +use OCA\Stackiq\Settings\StackiqAdmin; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting; @@ -64,10 +64,10 @@ public function __construct( * * @return JSONResponse `{available, enabled, directoryUrl, peers, staleAfter, message}`. * - * @AuthorizedAdminSetting(settings=OCA\SoftwareCatalog\Settings\SoftwareCatalogAdmin) + * @AuthorizedAdminSetting(settings=OCA\Stackiq\Settings\StackiqAdmin) * @spec openspec/specs/federated-catalog-sync/spec.md */ - #[AuthorizedAdminSetting(settings: SoftwareCatalogAdmin::class)] + #[AuthorizedAdminSetting(settings: StackiqAdmin::class)] public function status(): JSONResponse { return new JSONResponse(data: $this->federation->getStatus()); }//end status() @@ -79,10 +79,10 @@ public function status(): JSONResponse { * * @return JSONResponse `{ok, reason}` or a 400 when the peer is rejected. * - * @AuthorizedAdminSetting(settings=OCA\SoftwareCatalog\Settings\SoftwareCatalogAdmin) + * @AuthorizedAdminSetting(settings=OCA\Stackiq\Settings\StackiqAdmin) * @spec openspec/specs/federated-catalog-sync/spec.md */ - #[AuthorizedAdminSetting(settings: SoftwareCatalogAdmin::class)] + #[AuthorizedAdminSetting(settings: StackiqAdmin::class)] public function addPeer(string $peerUrl = ''): JSONResponse { $result = $this->federation->addPeer($peerUrl); if ($result['ok'] === false) { @@ -99,10 +99,10 @@ public function addPeer(string $peerUrl = ''): JSONResponse { * * @return JSONResponse `{ok, reason}` or a 400 when the peer is unknown. * - * @AuthorizedAdminSetting(settings=OCA\SoftwareCatalog\Settings\SoftwareCatalogAdmin) + * @AuthorizedAdminSetting(settings=OCA\Stackiq\Settings\StackiqAdmin) * @spec openspec/specs/federated-catalog-sync/spec.md */ - #[AuthorizedAdminSetting(settings: SoftwareCatalogAdmin::class)] + #[AuthorizedAdminSetting(settings: StackiqAdmin::class)] public function removePeer(string $peerUrl = ''): JSONResponse { $result = $this->federation->removePeer($peerUrl); if ($result['ok'] === false) { @@ -117,10 +117,10 @@ public function removePeer(string $peerUrl = ''): JSONResponse { * * @return JSONResponse `{ok, reason, peers}` or a 400 when federation is off/unavailable. * - * @AuthorizedAdminSetting(settings=OCA\SoftwareCatalog\Settings\SoftwareCatalogAdmin) + * @AuthorizedAdminSetting(settings=OCA\Stackiq\Settings\StackiqAdmin) * @spec openspec/specs/federated-catalog-sync/spec.md */ - #[AuthorizedAdminSetting(settings: SoftwareCatalogAdmin::class)] + #[AuthorizedAdminSetting(settings: StackiqAdmin::class)] public function pull(): JSONResponse { $result = $this->federation->pullAllPeers(); if ($result['ok'] === false) { diff --git a/lib/Controller/GebruikController.php b/lib/Controller/GebruikController.php index 0ae801b1..7f07267c 100644 --- a/lib/Controller/GebruikController.php +++ b/lib/Controller/GebruikController.php @@ -1,26 +1,26 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://github.com/nextcloud/softwarecatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; use Exception; -use OCA\SoftwareCatalog\Service\GebruikService; +use OCA\Stackiq\Service\GebruikService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\AnonRateLimit; @@ -38,12 +38,12 @@ * with role-based access for gebruik-beheerder and aanbod-beheerder users. * * @category Controller - * @package OCA\SoftwareCatalog\Controller + * @package OCA\Stackiq\Controller * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://github.com/nextcloud/softwarecatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/vendor-visibility-rbac/tasks.md#task-2 */ diff --git a/lib/Controller/IntakeController.php b/lib/Controller/IntakeController.php index f66b6815..7fbae2cf 100644 --- a/lib/Controller/IntakeController.php +++ b/lib/Controller/IntakeController.php @@ -17,11 +17,11 @@ * anonymous client has no CSRF token. * * @category Controller - * @package OCA\SoftwareCatalog\Controller + * @package OCA\Stackiq\Controller * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/open-data-publishing/spec.md * @@ -31,10 +31,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\AppInfo\Application; -use OCA\SoftwareCatalog\Service\IntakeService; +use OCA\Stackiq\AppInfo\Application; +use OCA\Stackiq\Service\IntakeService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\AnonRateLimit; diff --git a/lib/Controller/MergeController.php b/lib/Controller/MergeController.php index 2cb7ef15..63a20766 100644 --- a/lib/Controller/MergeController.php +++ b/lib/Controller/MergeController.php @@ -1,7 +1,7 @@ * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/organisation-merge/spec.md#requirement-both-merge-endpoints-must-be-admin-only-with-an-explicit-per-object-authorization-guard * @@ -29,10 +29,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\AppInfo\Application; -use OCA\SoftwareCatalog\Service\MergeOrganisatieService; +use OCA\Stackiq\AppInfo\Application; +use OCA\Stackiq\Service\MergeOrganisatieService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\NoAdminRequired; diff --git a/lib/Controller/ModerationController.php b/lib/Controller/ModerationController.php index d233f474..368bce09 100644 --- a/lib/Controller/ModerationController.php +++ b/lib/Controller/ModerationController.php @@ -13,7 +13,7 @@ * to `approved`/`rejected` — the schema's own `status`-conditioned public * RBAC rule does the visibility job `publicatiedatum` does for organisatie. * - * AUTH (ADR-005): every method is `#[AuthorizedAdminSetting(SoftwareCatalogAdmin::class)]` + * AUTH (ADR-005): every method is `#[AuthorizedAdminSetting(StackiqAdmin::class)]` * — Nextcloud's admin-settings middleware rejects any non-admin caller before * the controller body runs, so an authenticated non-admin can never reach the * approve/publish path (no privilege escalation / IDOR — OWASP A01:2021). The @@ -21,11 +21,11 @@ * currently `pending` and on peer-sourced (federated) mirrors. * * @category Controller - * @package OCA\SoftwareCatalog\Controller + * @package OCA\Stackiq\Controller * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/open-data-publishing/spec.md * @spec openspec/specs/catalog-ratings/spec.md#requirement-review-moderation-must-reuse-the-existing-moderation-queue-mechanism-not-a-second-one @@ -36,11 +36,11 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\AppInfo\Application; -use OCA\SoftwareCatalog\Service\ModerationService; -use OCA\SoftwareCatalog\Settings\SoftwareCatalogAdmin; +use OCA\Stackiq\AppInfo\Application; +use OCA\Stackiq\Service\ModerationService; +use OCA\Stackiq\Settings\StackiqAdmin; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting; @@ -74,11 +74,11 @@ public function __construct( * * @return JSONResponse `{ok, items}` or a 400. * - * @AuthorizedAdminSetting(settings=OCA\SoftwareCatalog\Settings\SoftwareCatalogAdmin) + * @AuthorizedAdminSetting(settings=OCA\Stackiq\Settings\StackiqAdmin) * @spec openspec/specs/open-data-publishing/spec.md * @spec openspec/specs/catalog-ratings/spec.md#requirement-review-moderation-must-reuse-the-existing-moderation-queue-mechanism-not-a-second-one */ - #[AuthorizedAdminSetting(settings: SoftwareCatalogAdmin::class)] + #[AuthorizedAdminSetting(settings: StackiqAdmin::class)] public function pending(string $type = ModerationService::MODERATED_TYPE): JSONResponse { $result = $this->moderation->listPending(type: $type); if ($result['ok'] === false) { @@ -96,11 +96,11 @@ public function pending(string $type = ModerationService::MODERATED_TYPE): JSONR * * @return JSONResponse `{ok, status}` or a 400. * - * @AuthorizedAdminSetting(settings=OCA\SoftwareCatalog\Settings\SoftwareCatalogAdmin) + * @AuthorizedAdminSetting(settings=OCA\Stackiq\Settings\StackiqAdmin) * @spec openspec/specs/open-data-publishing/spec.md * @spec openspec/specs/catalog-ratings/spec.md#requirement-a-newly-submitted-review-must-require-moderation-approval-before-becoming-public */ - #[AuthorizedAdminSetting(settings: SoftwareCatalogAdmin::class)] + #[AuthorizedAdminSetting(settings: StackiqAdmin::class)] public function approve(string $uuid, string $type = ModerationService::MODERATED_TYPE): JSONResponse { $result = $this->moderation->approve($uuid, type: $type); if ($result['ok'] === false) { @@ -118,11 +118,11 @@ public function approve(string $uuid, string $type = ModerationService::MODERATE * * @return JSONResponse `{ok, status}` or a 400. * - * @AuthorizedAdminSetting(settings=OCA\SoftwareCatalog\Settings\SoftwareCatalogAdmin) + * @AuthorizedAdminSetting(settings=OCA\Stackiq\Settings\StackiqAdmin) * @spec openspec/specs/open-data-publishing/spec.md * @spec openspec/specs/catalog-ratings/spec.md#requirement-a-newly-submitted-review-must-require-moderation-approval-before-becoming-public */ - #[AuthorizedAdminSetting(settings: SoftwareCatalogAdmin::class)] + #[AuthorizedAdminSetting(settings: StackiqAdmin::class)] public function reject(string $uuid, string $type = ModerationService::MODERATED_TYPE): JSONResponse { $result = $this->moderation->reject($uuid, type: $type); if ($result['ok'] === false) { diff --git a/lib/Controller/OrganisationMembersController.php b/lib/Controller/OrganisationMembersController.php index cc752432..2cc5304c 100644 --- a/lib/Controller/OrganisationMembersController.php +++ b/lib/Controller/OrganisationMembersController.php @@ -1,7 +1,7 @@ * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/multi-org-membership/spec.md#requirement-granting-or-revoking-organisation-access-must-be-restricted-to-a-beheerder-of-that-organisation-req-004 * @@ -40,9 +40,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\AppInfo\Application; +use OCA\OpenRegister\Service\OrganisationService; +use OCA\Stackiq\AppInfo\Application; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\NoAdminRequired; @@ -53,7 +54,6 @@ use OCP\IUserManager; use OCP\IUserSession; use Psr\Log\LoggerInterface; -use OCA\OpenRegister\Service\OrganisationService; /** * Beheerder-gated grant/revoke of organisation membership for an existing diff --git a/lib/Controller/PortfolioReportController.php b/lib/Controller/PortfolioReportController.php index fbde6b7f..bde7ad93 100644 --- a/lib/Controller/PortfolioReportController.php +++ b/lib/Controller/PortfolioReportController.php @@ -1,7 +1,7 @@ * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/portfolio-rationalization-time/specs/portfolio-rationalization-time/spec.md#requirement-report-and-csv-export-are-scoped-to-the-requesters-authorised-organisations * @@ -23,10 +23,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; use Exception; -use OCA\SoftwareCatalog\Service\PortfolioReportService; +use OCA\Stackiq\Service\PortfolioReportService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataDownloadResponse; diff --git a/lib/Controller/PreferencesController.php b/lib/Controller/PreferencesController.php index b813742b..f5672a18 100644 --- a/lib/Controller/PreferencesController.php +++ b/lib/Controller/PreferencesController.php @@ -1,7 +1,7 @@ * @copyright 2024 Conduction B.V. @@ -17,14 +17,14 @@ * * @version GIT: * - * @link https://codeberg.org/Conduction/softwarecatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\AppInfo\Application; +use OCA\Stackiq\AppInfo\Application; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; diff --git a/lib/Controller/PublicationController.php b/lib/Controller/PublicationController.php index dc908a7b..b6e4fe30 100644 --- a/lib/Controller/PublicationController.php +++ b/lib/Controller/PublicationController.php @@ -1,7 +1,7 @@ * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/open-data-publishing/spec.md * @@ -31,10 +31,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\AppInfo\Application; -use OCA\SoftwareCatalog\Service\PublicationService; +use OCA\Stackiq\AppInfo\Application; +use OCA\Stackiq\Service\PublicationService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\NoAdminRequired; diff --git a/lib/Controller/ReviewController.php b/lib/Controller/ReviewController.php index f9312948..becbe76c 100644 --- a/lib/Controller/ReviewController.php +++ b/lib/Controller/ReviewController.php @@ -14,11 +14,11 @@ * anonymous module/dienst detail page view, mirroring `FacetController`. * * @category Controller - * @package OCA\SoftwareCatalog\Controller + * @package OCA\Stackiq\Controller * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/catalog-ratings/spec.md * @@ -28,15 +28,15 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\AppInfo\Application; -use OCA\SoftwareCatalog\Service\ReviewAggregateService; -use OCA\SoftwareCatalog\Service\ReviewService; +use OCA\Stackiq\AppInfo\Application; +use OCA\Stackiq\Service\ReviewAggregateService; +use OCA\Stackiq\Service\ReviewService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; -use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\AnonRateLimit; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\JSONResponse; diff --git a/lib/Controller/SbomController.php b/lib/Controller/SbomController.php index 2bebb47c..1cfb557a 100644 --- a/lib/Controller/SbomController.php +++ b/lib/Controller/SbomController.php @@ -1,7 +1,7 @@ * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/sbom-import/spec.md * @@ -36,11 +36,11 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\AppInfo\Application; -use OCA\SoftwareCatalog\Exception\UnsupportedSbomFormatException; -use OCA\SoftwareCatalog\Service\SbomImportService; +use OCA\Stackiq\AppInfo\Application; +use OCA\Stackiq\Exception\UnsupportedSbomFormatException; +use OCA\Stackiq\Service\SbomImportService; use OCP\AppFramework\Controller; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; @@ -69,6 +69,12 @@ class SbomController extends Controller { * group membership OR manage-ACL on the target moduleVersie's parent * module"). * + * `software-catalog-admins` is FROZEN across the stackiq -> stackiq + * rename: it is a Nextcloud group id, and membership is stored against that + * literal in `oc_group_user`. Renaming it makes every membership check miss + * without raising anything, so the app would silently drop the permissions + * of everyone currently in the group. + * * @var array */ private const MANAGE_GROUPS = ['software-catalog-admins', 'aanbod-beheerder', 'functioneel-beheerder']; diff --git a/lib/Controller/Settings/ModuleRegistrationHandler.php b/lib/Controller/Settings/ModuleRegistrationHandler.php index 0c13d806..31eec685 100644 --- a/lib/Controller/Settings/ModuleRegistrationHandler.php +++ b/lib/Controller/Settings/ModuleRegistrationHandler.php @@ -7,11 +7,11 @@ * and CouplingBetweenObjects on that controller. * * @category Handler - * @package OCA\SoftwareCatalog\Controller\Settings + * @package OCA\Stackiq\Controller\Settings * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/method-decomposition/tasks.md#task-3 * @@ -21,9 +21,9 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller\Settings; +namespace OCA\Stackiq\Controller\Settings; -use OCA\SoftwareCatalog\Service\ModuleRegistrationService; +use OCA\Stackiq\Service\ModuleRegistrationService; use Psr\Log\LoggerInterface; /** diff --git a/lib/Controller/Settings/SyncHandler.php b/lib/Controller/Settings/SyncHandler.php index 77971911..e96ffe0c 100644 --- a/lib/Controller/Settings/SyncHandler.php +++ b/lib/Controller/Settings/SyncHandler.php @@ -7,11 +7,11 @@ * and CouplingBetweenObjects on that controller. * * @category Handler - * @package OCA\SoftwareCatalog\Controller\Settings + * @package OCA\Stackiq\Controller\Settings * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/method-decomposition/tasks.md#task-3 * @@ -21,9 +21,9 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Controller\Settings; +namespace OCA\Stackiq\Controller\Settings; -use OCA\SoftwareCatalog\Service\OrganizationSyncService; +use OCA\Stackiq\Service\OrganizationSyncService; use Psr\Log\LoggerInterface; /** diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 5bc0f6af..2064ade2 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -22,15 +22,15 @@ * SPDX-License-Identifier: EUPL-1.2 */ -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\OpenRegister\Service\ConfigurationService; use OCA\OpenRegister\Contract\ObjectServiceInterface; -use OCA\SoftwareCatalog\Service\ArchiMateService; -use OCA\SoftwareCatalog\Service\EolSyncService; -use OCA\SoftwareCatalog\Service\OrganizationSyncService; -use OCA\SoftwareCatalog\Service\ProgressTracker; -use OCA\SoftwareCatalog\Service\SettingsService; +use OCA\OpenRegister\Service\ConfigurationService; +use OCA\Stackiq\Service\ArchiMateService; +use OCA\Stackiq\Service\EolSyncService; +use OCA\Stackiq\Service\OrganizationSyncService; +use OCA\Stackiq\Service\ProgressTracker; +use OCA\Stackiq\Service\SettingsService; use OCP\App\IAppManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; @@ -578,7 +578,7 @@ public function load(): JSONResponse { }//end load() /** - * Initialize the SoftwareCatalog settings + * Initialize the Stackiq settings * * @return JSONResponse JSON response containing the initialization results * @@ -629,7 +629,7 @@ public function status(): JSONResponse { 'versionInfo' => $versionInfo, 'timestamp' => time(), 'autoConfigCompleted' => $this->config->getValueString( - 'softwarecatalog', + 'stackiq', 'auto_config_completed', 'false' ) === 'true', @@ -801,7 +801,7 @@ public function sendTestEmail(): JSONResponse { ); } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog: Failed to send test email in controller', + 'Stackiq: Failed to send test email in controller', [ 'exception_class' => get_class($e), 'exception_message' => $e->getMessage(), @@ -1915,14 +1915,14 @@ public function testEmailConnection(): JSONResponse { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } - $this->logger->info('SoftwareCatalog: Email connection test endpoint called'); + $this->logger->info('Stackiq: Email connection test endpoint called'); try { $data = $this->request->getParams(); $emailSettings = $data['emailSettings'] ?? $data ?? []; $this->logger->info( - 'SoftwareCatalog: Email connection test request data', + 'Stackiq: Email connection test request data', [ 'has_email_settings' => empty($emailSettings) === false, 'transport_type' => $emailSettings['transportType'] ?? 'not specified', @@ -1933,7 +1933,7 @@ public function testEmailConnection(): JSONResponse { $result = $this->settingsService->testEmailConnection($emailSettings); $this->logger->info( - 'SoftwareCatalog: Email connection test result from service', + 'Stackiq: Email connection test result from service', [ 'success' => $result['success'], 'message' => $result['message'] ?? 'no message', @@ -1949,7 +1949,7 @@ public function testEmailConnection(): JSONResponse { ); } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog: Failed to test email connection', + 'Stackiq: Failed to test email connection', [ 'exception_class' => get_class($e), 'exception_message' => $e->getMessage(), @@ -2876,13 +2876,13 @@ public function testArchiMateRoundTrip(): JSONResponse { } try { - $this->logger->info('SoftwareCatalog: ArchiMate round-trip test started'); + $this->logger->info('Stackiq: ArchiMate round-trip test started'); // Call the ArchiMate service to perform round-trip test. $result = $this->archiMateService->testRoundTrip(); $this->logger->info( - 'SoftwareCatalog: ArchiMate round-trip test completed', + 'Stackiq: ArchiMate round-trip test completed', [ 'success' => $result['success'], 'message' => $result['message'] ?? 'no message', @@ -2899,7 +2899,7 @@ public function testArchiMateRoundTrip(): JSONResponse { ); } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog: ArchiMate round-trip test failed', + 'Stackiq: ArchiMate round-trip test failed', [ 'exception_class' => get_class($e), 'exception_message' => $e->getMessage(), @@ -3596,7 +3596,7 @@ public function bulkSyncStandards(): JSONResponse { $this->logger->info('SettingsController: Starting bulk sync of module standards.'); // Get the ModuleComplianceService from the container. - $moduleComplianceService = $this->container->get(\OCA\SoftwareCatalog\Service\ModuleComplianceService::class); + $moduleComplianceService = $this->container->get(\OCA\Stackiq\Service\ModuleComplianceService::class); // Perform the bulk sync. $results = $moduleComplianceService->bulkSyncModuleStandards(); diff --git a/lib/Controller/ViewController.php b/lib/Controller/ViewController.php index f39199ce..1b84d49e 100644 --- a/lib/Controller/ViewController.php +++ b/lib/Controller/ViewController.php @@ -1,25 +1,25 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://github.com/nextcloud/softwarecatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ -namespace OCA\SoftwareCatalog\Controller; +namespace OCA\Stackiq\Controller; -use OCA\SoftwareCatalog\Service\ViewService; +use OCA\Stackiq\Service\ViewService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; @@ -34,12 +34,12 @@ * with optional enrichment capabilities for products, usage data (gebruik), and related information. * * @category Controller - * @package OCA\SoftwareCatalog\Controller + * @package OCA\Stackiq\Controller * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://github.com/nextcloud/softwarecatalog + * @link https://github.com/ConductionNL/stackiq */ class ViewController extends Controller { /** @@ -377,7 +377,7 @@ public function getApiDocumentation(): JSONResponse { $documentation = [ 'api_version' => '1.0.0', - 'description' => 'SoftwareCatalog View API - Query and enrich ArchiMate views', + 'description' => 'Stackiq View API - Query and enrich ArchiMate views', 'base_url' => '/api/views', 'endpoints' => [ [ diff --git a/lib/Dashboard/ConceptOrganisatiesWidget.php b/lib/Dashboard/ConceptOrganisatiesWidget.php index d2f8f1d7..2c7d7297 100644 --- a/lib/Dashboard/ConceptOrganisatiesWidget.php +++ b/lib/Dashboard/ConceptOrganisatiesWidget.php @@ -4,17 +4,17 @@ * Concept Organisaties Dashboard Widget. * * @category Dashboard - * @package OCA\SoftwareCatalog\Dashboard + * @package OCA\Stackiq\Dashboard * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ -namespace OCA\SoftwareCatalog\Dashboard; +namespace OCA\Stackiq\Dashboard; -use OCA\SoftwareCatalog\AppInfo\Application; +use OCA\Stackiq\AppInfo\Application; use OCP\Dashboard\IWidget; use OCP\IL10N; use OCP\IURLGenerator; @@ -39,7 +39,13 @@ public function __construct( * @return string The widget ID */ public function getId(): string { - return 'softwarecatalog_concept_organisaties_widget'; + // FROZEN across the stackiq -> stackiq rename. The Dashboard app + // stores each user's chosen widgets BY WIDGET ID, in its own `dashboard` + // appid namespace in `oc_preferences` — data this app's repair steps + // cannot reach. Renaming this id therefore does not error: the widget + // simply stops matching the stored selection and silently vanishes from + // every dashboard that had it. + return 'stackiq_concept_organisaties_widget'; }//end getId() /** @@ -66,7 +72,7 @@ public function getOrder(): int { * @return string The icon CSS class name */ public function getIconClass(): string { - return 'icon-softwarecatalog-widget'; + return 'icon-stackiq-widget'; }//end getIconClass() /** diff --git a/lib/EventListener/DecisionConcludedListener.php b/lib/EventListener/DecisionConcludedListener.php index c9fa995b..682747be 100644 --- a/lib/EventListener/DecisionConcludedListener.php +++ b/lib/EventListener/DecisionConcludedListener.php @@ -1,24 +1,24 @@ Actief` transition is reached ONLY here, as * a projection of an `approved` decidesk outcome — never on local authority. * * @category EventListener - * @package OCA\SoftwareCatalog\EventListener + * @package OCA\Stackiq\EventListener * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/contract-decision-delegation/spec.md * @@ -28,10 +28,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\EventListener; +namespace OCA\Stackiq\EventListener; use OCA\Decidesk\Event\DecisionConcludedEvent; -use OCA\SoftwareCatalog\Service\ContractApprovalService; +use OCA\Stackiq\Service\ContractApprovalService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use Psr\Log\LoggerInterface; @@ -59,7 +59,7 @@ public function __construct( /** * Handle a concluded decidesk Decision. * - * Only `DecisionConcludedEvent`s whose `sourceApp` is softwarecatalog are + * Only `DecisionConcludedEvent`s whose `sourceApp` is stackiq are * acted on; everything else is ignored. The carried `decisionId` is * IDOR-checked against the contract's stored `approvalDecisionId` inside * `resolveContractForOutcome()` before any projection is written. diff --git a/lib/EventListener/ModuleComplianceSubscriber.php b/lib/EventListener/ModuleComplianceSubscriber.php index 478beb70..d751ad60 100644 --- a/lib/EventListener/ModuleComplianceSubscriber.php +++ b/lib/EventListener/ModuleComplianceSubscriber.php @@ -4,26 +4,26 @@ * Module Compliance Subscriber. * * This file contains the subscriber class for handling module compliance updates - * in the SoftwareCatalog application. + * in the Stackiq application. * * @category EventListener - * @package OCA\SoftwareCatalog\EventListener + * @package OCA\Stackiq\EventListener * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\EventListener; +namespace OCA\Stackiq\EventListener; use OCA\OpenRegister\Event\ObjectCreatedEvent; use OCA\OpenRegister\Event\ObjectUpdatedEvent; -use OCA\SoftwareCatalog\Service\ModuleComplianceService; -use OCA\SoftwareCatalog\Service\ModuleVersionService; -use OCA\SoftwareCatalog\Service\SettingsService; +use OCA\Stackiq\Service\ModuleComplianceService; +use OCA\Stackiq\Service\ModuleVersionService; +use OCA\Stackiq\Service\SettingsService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use Psr\Container\ContainerInterface; @@ -36,11 +36,11 @@ * synchronizes the 'standards' property based on linked compliance objects. * * @category EventListener - * @package OCA\SoftwareCatalog\EventListener + * @package OCA\Stackiq\EventListener * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ class ModuleComplianceSubscriber implements IEventListener { /** diff --git a/lib/EventListener/ModuleRegistrationSubscriber.php b/lib/EventListener/ModuleRegistrationSubscriber.php index 267ed084..ec8612ae 100644 --- a/lib/EventListener/ModuleRegistrationSubscriber.php +++ b/lib/EventListener/ModuleRegistrationSubscriber.php @@ -7,22 +7,22 @@ * based on the owning organisation's type. * * @category EventListener - * @package OCA\SoftwareCatalog\EventListener + * @package OCA\Stackiq\EventListener * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\EventListener; +namespace OCA\Stackiq\EventListener; use OCA\OpenRegister\Event\ObjectCreatedEvent; use OCA\OpenRegister\Event\ObjectUpdatedEvent; -use OCA\SoftwareCatalog\Service\ModuleRegistrationService; -use OCA\SoftwareCatalog\Service\SettingsService; +use OCA\Stackiq\Service\ModuleRegistrationService; +use OCA\Stackiq\Service\SettingsService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use Psr\Container\ContainerInterface; @@ -33,7 +33,7 @@ * based on the owning organisation's type. * * @category EventListener - * @package OCA\SoftwareCatalog\EventListener + * @package OCA\Stackiq\EventListener */ class ModuleRegistrationSubscriber implements IEventListener { /** diff --git a/lib/EventListener/OpenRegisterEventsDebugListener.php b/lib/EventListener/OpenRegisterEventsDebugListener.php index 87118c31..4416542e 100644 --- a/lib/EventListener/OpenRegisterEventsDebugListener.php +++ b/lib/EventListener/OpenRegisterEventsDebugListener.php @@ -1,14 +1,14 @@ * @copyright 2024 Conduction B.V. @@ -16,14 +16,14 @@ * * @version GIT: * - * @link https://SoftwareCatalog.app + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\EventListener; +namespace OCA\Stackiq\EventListener; use OCA\OpenRegister\Event\ObjectCreatedEvent; use OCA\OpenRegister\Event\ObjectDeletedEvent; @@ -43,10 +43,10 @@ use Psr\Log\LoggerInterface; /** - * Debug event listener for all OpenRegister events in SoftwareCatalog + * Debug event listener for all OpenRegister events in Stackiq * * This listener provides comprehensive debugging information for all OpenRegister events - * received by the SoftwareCatalog app. It logs event details at info level and can be + * received by the Stackiq app. It logs event details at info level and can be * easily enabled/disabled. * * @template T of Event @@ -111,7 +111,7 @@ public function handle(Event $event): void { $this->logger->debug( 'OpenRegister debug listener triggered', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'eventType' => $eventType, 'eventClass' => $eventClass, 'debugEnabled' => $this->debugEnabled, @@ -119,7 +119,7 @@ public function handle(Event $event): void { ); if ($this->debugEnabled === false) { - $this->logger->warning('SoftwareCatalog OpenRegister Debug: Debug disabled, skipping detailed logging.'); + $this->logger->warning('Stackiq OpenRegister Debug: Debug disabled, skipping detailed logging.'); return; } @@ -128,9 +128,9 @@ public function handle(Event $event): void { // Log comprehensive debug information. $this->logger->info( - '[SoftwareCatalog] OPENREGISTER EVENT: {eventType} received from OpenRegister', + '[Stackiq] OPENREGISTER EVENT: {eventType} received from OpenRegister', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'eventType' => $eventType, 'eventClass' => $eventClass, 'listenerClass' => self::class, @@ -192,7 +192,7 @@ private function extractEventData(Event $event): array { } $data['eventType'] = 'Unknown'; - $data['note'] = 'Event type not specifically handled by SoftwareCatalog debug listener'; + $data['note'] = 'Event type not specifically handled by Stackiq debug listener'; return $data; }//end extractEventData() diff --git a/lib/EventListener/SoftwareCatalogEventListener.php b/lib/EventListener/StackiqEventListener.php similarity index 87% rename from lib/EventListener/SoftwareCatalogEventListener.php rename to lib/EventListener/StackiqEventListener.php index 73d18ea2..5f2cf672 100644 --- a/lib/EventListener/SoftwareCatalogEventListener.php +++ b/lib/EventListener/StackiqEventListener.php @@ -1,13 +1,13 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -19,7 +19,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\EventListener; +namespace OCA\Stackiq\EventListener; use OCA\OpenRegister\Event\ObjectCreatedEvent; use OCA\OpenRegister\Event\ObjectDeletedEvent; @@ -27,9 +27,9 @@ use OCA\OpenRegister\Event\ObjectRevertedEvent; use OCA\OpenRegister\Event\ObjectUnlockedEvent; use OCA\OpenRegister\Event\ObjectUpdatedEvent; -use OCA\SoftwareCatalog\Service\ContactpersoonService; -use OCA\SoftwareCatalog\Service\GebruikSyncService; -use OCA\SoftwareCatalog\Service\SettingsService; +use OCA\Stackiq\Service\ContactpersoonService; +use OCA\Stackiq\Service\GebruikSyncService; +use OCA\Stackiq\Service\SettingsService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use Psr\Container\ContainerInterface; @@ -43,7 +43,7 @@ * user blocking/unblocking functionality. * * @category EventListener - * @package OCA\SoftwareCatalog\EventListener + * @package OCA\Stackiq\EventListener * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: @@ -53,9 +53,9 @@ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class SoftwareCatalogEventListener implements IEventListener { +class StackiqEventListener implements IEventListener { /** - * Constructor for SoftwareCatalogEventListener + * Constructor for StackiqEventListener * * @param ContainerInterface $container DI container for lazy service resolution. */ @@ -83,7 +83,7 @@ public function handle(Event $event): void { $settingsService = $this->container->get(SettingsService::class); $logger->info( - 'SoftwareCatalog: Processing event', + 'Stackiq: Processing event', [ 'eventType' => get_class($event), 'timestamp' => date('Y-m-d H:i:s'), @@ -100,7 +100,7 @@ public function handle(Event $event): void { try { $logger = $this->container->get(LoggerInterface::class); $logger->error( - 'SoftwareCatalog: Error in event handler', + 'Stackiq: Error in event handler', [ 'eventType' => get_class($event), 'exception' => $e->getMessage(), @@ -171,7 +171,7 @@ private function dispatchEvent( || $event instanceof ObjectRevertedEvent ) { $logger->debug( - 'SoftwareCatalog: Ignoring object lifecycle event', + 'Stackiq: Ignoring object lifecycle event', [ 'eventType' => get_class($event), ] @@ -261,10 +261,10 @@ private function runOrganizationSync( ): void { $objectId = $object->getUuid(); try { - $orgSyncService = $this->container->get('OCA\SoftwareCatalog\Service\OrganizationSyncService'); + $orgSyncService = $this->container->get('OCA\Stackiq\Service\OrganizationSyncService'); $result = $orgSyncService->processSpecificOrganization($object); $logger->info( - 'SoftwareCatalog: Successfully processed organization ' . $phase, + 'Stackiq: Successfully processed organization ' . $phase, [ 'objectId' => $objectId, 'processResult' => $result, @@ -272,7 +272,7 @@ private function runOrganizationSync( ); } catch (\Exception $e) { $logger->error( - 'SoftwareCatalog: Failed to process organization ' . $phase, + 'Stackiq: Failed to process organization ' . $phase, [ 'objectId' => $objectId, 'exception' => $e->getMessage(), @@ -309,7 +309,7 @@ private function runGebruikSync( $gebruikSyncService = $this->container->get(GebruikSyncService::class); $result = $gebruikSyncService->processSpecificGebruik($object); $logger->info( - 'SoftwareCatalog: Successfully processed gebruik ' . $phase, + 'Stackiq: Successfully processed gebruik ' . $phase, [ 'objectId' => $objectId, 'processResult' => $result, @@ -317,7 +317,7 @@ private function runGebruikSync( ); } catch (\Exception $e) { $logger->error( - 'SoftwareCatalog: Failed to process gebruik ' . $phase, + 'Stackiq: Failed to process gebruik ' . $phase, [ 'objectId' => $objectId, 'exception' => $e->getMessage(), @@ -366,7 +366,7 @@ private function refetchOrganizationWithContactpersonen( ); $logger->info( - 'SoftwareCatalog: Refetched organization with contactpersonen', + 'Stackiq: Refetched organization with contactpersonen', [ 'objectId' => $objectId, 'contactpersonenCount' => count( @@ -378,7 +378,7 @@ private function refetchOrganizationWithContactpersonen( return $orgWithContacts; } catch (\Exception $e) { $logger->error( - 'SoftwareCatalog: Failed to refetch organization with contactpersonen', + 'Stackiq: Failed to refetch organization with contactpersonen', [ 'objectId' => $objectId, 'exception' => $e->getMessage(), @@ -414,7 +414,7 @@ private function handleObjectCreated( ): void { $object = $event->getObject(); if ($object === null) { - $logger->warning('SoftwareCatalog: ObjectCreatedEvent received with null object'); + $logger->warning('Stackiq: ObjectCreatedEvent received with null object'); return; } @@ -426,7 +426,7 @@ private function handleObjectCreated( $objectSchemaIdInt = (int)$objectSchemaId; $logger->info( - 'SoftwareCatalog: Processing object creation', + 'Stackiq: Processing object creation', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, @@ -444,7 +444,7 @@ private function handleObjectCreated( $gebruikSchemaId = $catalogSchemaIds['usage']; $logger->debug( - 'SoftwareCatalog: Configuration lookup results', + 'Stackiq: Configuration lookup results', [ 'organisatieSchemaId' => $organisationSchemaId, 'contactpersoonSchemaId' => $contactSchemaId, @@ -462,7 +462,7 @@ private function handleObjectCreated( // Only process active organizations. if ($this->isActiveStatus(status: $status) === false) { $logger->debug( - 'SoftwareCatalog: Skipping non-active organization creation', + 'Stackiq: Skipping non-active organization creation', [ 'objectId' => $objectId, 'status' => $status, @@ -472,7 +472,7 @@ private function handleObjectCreated( } $logger->info( - 'SoftwareCatalog: Processing active organization creation', + 'Stackiq: Processing active organization creation', [ 'objectId' => $objectId, 'status' => $status, @@ -485,28 +485,28 @@ private function handleObjectCreated( // Check if this is a contactpersoon object. if ($this->matchesSchema(objectSchemaIdInt: $objectSchemaIdInt, configured: $contactSchemaId) === true) { - $logger->info('SoftwareCatalog: Processing contactpersoon creation', ['objectId' => $objectId]); + $logger->info('Stackiq: Processing contactpersoon creation', ['objectId' => $objectId]); $contactSvc->processContactpersoon($object); return; } // Check if this is a contactgegevens object (deprecated - use contactpersoon instead). if ($this->matchesSchema(objectSchemaIdInt: $objectSchemaIdInt, configured: $contactInfoSchemaId) === true) { - $logger->info('SoftwareCatalog: Processing contactgegevens creation (deprecated)', ['objectId' => $objectId]); + $logger->info('Stackiq: Processing contactgegevens creation (deprecated)', ['objectId' => $objectId]); // Contactgegevens is deprecated, use contactpersoon instead. return; } // Check if this is a gebruik object. if ($this->matchesSchema(objectSchemaIdInt: $objectSchemaIdInt, configured: $gebruikSchemaId) === true) { - $logger->info('SoftwareCatalog: Processing gebruik creation', ['objectId' => $objectId]); + $logger->info('Stackiq: Processing gebruik creation', ['objectId' => $objectId]); $this->runGebruikSync(object: $object, phase: 'creation', logger: $logger); return; }//end if // Log unhandled object types. $logger->debug( - 'SoftwareCatalog: Object creation not handled - not a supported object type', + 'Stackiq: Object creation not handled - not a supported object type', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaIdInt, @@ -547,7 +547,7 @@ private function handleObjectUpdated( $oldObject = $event->getOldObject(); if ($object === null) { - $logger->warning('SoftwareCatalog: ObjectUpdatedEvent received with null object'); + $logger->warning('Stackiq: ObjectUpdatedEvent received with null object'); return; } @@ -559,7 +559,7 @@ private function handleObjectUpdated( $objectSchemaIdInt = (int)$objectSchemaId; $logger->info( - 'SoftwareCatalog: Processing object update', + 'Stackiq: Processing object update', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, @@ -576,7 +576,7 @@ private function handleObjectUpdated( $logger->debug( 'Got organisation schema ID', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organisatieSchemaId' => $organisationSchemaId, 'organisatieSchemaIdInt' => $orgSchemaIdInt, ] @@ -585,7 +585,7 @@ private function handleObjectUpdated( $logger->debug( 'Organization schema check', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'objectSchemaId' => $objectSchemaId, 'objectSchemaIdInt' => $objectSchemaIdInt, 'organisatieSchemaId' => $organisationSchemaId, @@ -607,7 +607,7 @@ private function handleObjectUpdated( $logger->debug( 'Organization status check', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'objectId' => $objectId, 'status' => $status, 'oldStatus' => $oldStatus, @@ -621,7 +621,7 @@ private function handleObjectUpdated( // Only process active organizations. if ($this->isActiveStatus(status: $status) === true && $status !== $oldStatus) { $logger->info( - 'SoftwareCatalog: Processing active organization update', + 'Stackiq: Processing active organization update', [ 'objectId' => $objectId, 'status' => $status, @@ -641,7 +641,7 @@ private function handleObjectUpdated( if ($this->isActiveStatus(status: $status) === false || $status === $oldStatus) { $logger->debug( - 'SoftwareCatalog: Skipping non-active organization update', + 'Stackiq: Skipping non-active organization update', [ 'objectId' => $objectId, 'status' => $status, @@ -659,7 +659,7 @@ private function handleObjectUpdated( if ($contactSchemaId !== null && $objectSchemaIdInt === $cntSchemaIdInt) { $logger->info( - 'SoftwareCatalog: Matched contactpersoon schema - processing update', + 'Stackiq: Matched contactpersoon schema - processing update', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, @@ -674,7 +674,7 @@ private function handleObjectUpdated( ); $logger->info( - 'SoftwareCatalog: Successfully processed contactpersoon update', + 'Stackiq: Successfully processed contactpersoon update', [ 'objectId' => $objectId, 'timestamp' => date('Y-m-d H:i:s'), @@ -682,7 +682,7 @@ private function handleObjectUpdated( ); } catch (\Exception $e) { $logger->error( - 'SoftwareCatalog: Failed to process contactpersoon update', + 'Stackiq: Failed to process contactpersoon update', [ 'objectId' => $objectId, 'exception' => $e->getMessage(), @@ -702,7 +702,7 @@ private function handleObjectUpdated( if ($contactInfoSchemaId !== null && $objectSchemaIdInt === $infoSchemaIdInt) { $logger->info( - 'SoftwareCatalog: Matched contactgegevens schema - processing update (backward compatibility)', + 'Stackiq: Matched contactgegevens schema - processing update (backward compatibility)', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, @@ -718,7 +718,7 @@ private function handleObjectUpdated( ); $logger->info( - 'SoftwareCatalog: Successfully processed contactgegevens update (as contactpersoon)', + 'Stackiq: Successfully processed contactgegevens update (as contactpersoon)', [ 'objectId' => $objectId, 'timestamp' => date('Y-m-d H:i:s'), @@ -726,7 +726,7 @@ private function handleObjectUpdated( ); } catch (\Exception $e) { $logger->error( - 'SoftwareCatalog: Failed to process contactgegevens update', + 'Stackiq: Failed to process contactgegevens update', [ 'objectId' => $objectId, 'exception' => $e->getMessage(), @@ -746,7 +746,7 @@ private function handleObjectUpdated( if ($gebruikSchemaId !== null && $objectSchemaIdInt === $gebruikSchemaIdInt) { $logger->info( - 'SoftwareCatalog: Matched gebruik schema - processing update', + 'Stackiq: Matched gebruik schema - processing update', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, @@ -760,7 +760,7 @@ private function handleObjectUpdated( // Log if we don't handle this schema type. $logger->debug( - 'SoftwareCatalog: Object update not handled - focusing only on organisatie, contactpersonen, and gebruik', + 'Stackiq: Object update not handled - focusing only on organisatie, contactpersonen, and gebruik', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, @@ -801,7 +801,7 @@ private function handleObjectDeleted( ): void { $object = $event->getObject(); if ($object === null) { - $logger->warning('SoftwareCatalog: ObjectDeletedEvent received with null object'); + $logger->warning('Stackiq: ObjectDeletedEvent received with null object'); return; } @@ -810,7 +810,7 @@ private function handleObjectDeleted( $objectRegisterId = $object->getRegister(); $logger->info( - 'SoftwareCatalog: Processing object deletion', + 'Stackiq: Processing object deletion', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, @@ -825,7 +825,7 @@ private function handleObjectDeleted( $objectSchemaIdInt = (int)$objectSchemaId; if ($organisationSchemaId !== null && $objectSchemaIdInt === $orgSchemaIdInt) { - $logger->info('SoftwareCatalog: Processing organization deletion', ['objectId' => $objectId]); + $logger->info('Stackiq: Processing organization deletion', ['objectId' => $objectId]); $this->runOrganizationSync(object: $object, phase: 'deletion', logger: $logger); return; }//end if @@ -836,7 +836,7 @@ private function handleObjectDeleted( if ($contactSchemaId !== null && $objectSchemaIdInt === $cntSchemaIdInt) { $logger->info( - 'SoftwareCatalog: Matched contactpersoon schema - processing deletion', + 'Stackiq: Matched contactpersoon schema - processing deletion', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, @@ -848,7 +848,7 @@ private function handleObjectDeleted( $contactSvc->handleContactDeletion($object); $logger->info( - 'SoftwareCatalog: Successfully processed contactpersoon deletion', + 'Stackiq: Successfully processed contactpersoon deletion', [ 'objectId' => $objectId, 'timestamp' => date('Y-m-d H:i:s'), @@ -856,7 +856,7 @@ private function handleObjectDeleted( ); } catch (\Exception $e) { $logger->error( - 'SoftwareCatalog: Failed to process contactpersoon deletion', + 'Stackiq: Failed to process contactpersoon deletion', [ 'objectId' => $objectId, 'exception' => $e->getMessage(), @@ -876,7 +876,7 @@ private function handleObjectDeleted( if ($contactInfoSchemaId !== null && $objectSchemaIdInt === $infoSchemaIdInt) { $logger->info( - 'SoftwareCatalog: Matched contactgegevens schema - processing deletion (backward compatibility)', + 'Stackiq: Matched contactgegevens schema - processing deletion (backward compatibility)', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, @@ -888,7 +888,7 @@ private function handleObjectDeleted( $contactSvc->handleContactDeletion($object); $logger->info( - 'SoftwareCatalog: Successfully processed contactgegevens deletion', + 'Stackiq: Successfully processed contactgegevens deletion', [ 'objectId' => $objectId, 'timestamp' => date('Y-m-d H:i:s'), @@ -896,7 +896,7 @@ private function handleObjectDeleted( ); } catch (\Exception $e) { $logger->error( - 'SoftwareCatalog: Failed to process contactgegevens deletion', + 'Stackiq: Failed to process contactgegevens deletion', [ 'objectId' => $objectId, 'exception' => $e->getMessage(), @@ -918,7 +918,7 @@ private function handleObjectDeleted( $objectData = $object->getObject(); $logger->info( - 'SoftwareCatalog: Matched gebruik schema - processing deletion', + 'Stackiq: Matched gebruik schema - processing deletion', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, @@ -931,7 +931,7 @@ private function handleObjectDeleted( // For deletions, we mainly log the event since the object is being removed. // No specific cleanup needed for gebruik objects currently. $logger->info( - 'SoftwareCatalog: Gebruik object deleted - no specific cleanup required', + 'Stackiq: Gebruik object deleted - no specific cleanup required', [ 'objectId' => $objectId, 'timestamp' => date('Y-m-d H:i:s'), @@ -942,7 +942,7 @@ private function handleObjectDeleted( // Log if we don't handle this schema type. $logger->debug( - 'SoftwareCatalog: Object deletion not handled - focusing only on organisatie, contactpersonen, and gebruik', + 'Stackiq: Object deletion not handled - focusing only on organisatie, contactpersonen, and gebruik', [ 'objectId' => $objectId, 'schemaId' => $objectSchemaId, diff --git a/lib/EventListener/TestEventListener.php b/lib/EventListener/TestEventListener.php index 83ed303e..c55d0250 100644 --- a/lib/EventListener/TestEventListener.php +++ b/lib/EventListener/TestEventListener.php @@ -1,13 +1,13 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -17,7 +17,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\EventListener; +namespace OCA\Stackiq\EventListener; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; @@ -32,7 +32,7 @@ * triggered for testing purposes. * * @category EventListener - * @package OCA\SoftwareCatalog\EventListener + * @package OCA\Stackiq\EventListener * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: @@ -63,7 +63,7 @@ public function __construct( public function handle(Event $event): void { // Log that we received ANY event first. $this->logger->info( - 'SoftwareCatalog TestEventListener: Event received!', + 'Stackiq TestEventListener: Event received!', [ 'eventClass' => get_class($event), 'timestamp' => date('Y-m-d H:i:s'), @@ -75,7 +75,7 @@ public function handle(Event $event): void { if (($event instanceof UserLoggedInEvent) === false) { // Log other events we might receive. $this->logger->debug( - 'SoftwareCatalog TestEventListener: Received unhandled event', + 'Stackiq TestEventListener: Received unhandled event', [ 'eventClass' => get_class($event), 'timestamp' => date('Y-m-d H:i:s'), @@ -87,7 +87,7 @@ public function handle(Event $event): void { $user = $event->getUser(); $this->logger->info( - 'SoftwareCatalog TestEventListener: User logged in successfully!', + 'Stackiq TestEventListener: User logged in successfully!', [ 'userId' => $user->getUID(), 'userDisplayName' => $user->getDisplayName(), @@ -100,7 +100,7 @@ public function handle(Event $event): void { // Test that we can access Nextcloud services. try { $this->logger->debug( - 'SoftwareCatalog TestEventListener: Event listener is working correctly!', + 'Stackiq TestEventListener: Event listener is working correctly!', [ 'message' => 'This confirms that event listeners are properly registered and triggered', 'userId' => $user->getUID(), @@ -109,7 +109,7 @@ public function handle(Event $event): void { ); } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog TestEventListener: Error in event processing', + 'Stackiq TestEventListener: Error in event processing', [ 'exception' => $e->getMessage(), 'trace' => $e->getTraceAsString(), diff --git a/lib/EventListener/UserProfileUpdatedEventListener.php b/lib/EventListener/UserProfileUpdatedEventListener.php index 6bbb4c42..a20c2e36 100644 --- a/lib/EventListener/UserProfileUpdatedEventListener.php +++ b/lib/EventListener/UserProfileUpdatedEventListener.php @@ -7,7 +7,7 @@ * the changed fields back to the corresponding contactpersoon object. * * @category EventListener - * @package OCA\SoftwareCatalog\EventListener + * @package OCA\Stackiq\EventListener * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -17,15 +17,15 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\EventListener; +namespace OCA\Stackiq\EventListener; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Event\UserProfileUpdatedEvent; -use OCA\SoftwareCatalog\Service\SettingsService; +use OCA\Stackiq\Service\SettingsService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; -use OCA\OpenRegister\Contract\ObjectServiceInterface; /** * Syncs user profile changes to the corresponding contactpersoon object. diff --git a/lib/Examples/ContactpersoonServiceExample.php b/lib/Examples/ContactpersoonServiceExample.php index 5c82ddc0..ce3b5420 100644 --- a/lib/Examples/ContactpersoonServiceExample.php +++ b/lib/Examples/ContactpersoonServiceExample.php @@ -7,30 +7,30 @@ * method to retrieve contact persons for an organization with their user details spliced in. * * @category Example - * @package OCA\SoftwareCatalog\Examples + * @package OCA\Stackiq\Examples * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Examples; +namespace OCA\Stackiq\Examples; -use OCA\SoftwareCatalog\Service\ContactpersoonService; +use OCA\Stackiq\Service\ContactpersoonService; use Psr\Log\LoggerInterface; /** * Example class demonstrating ContactpersoonService usage. * * @category Example - * @package OCA\SoftwareCatalog\Examples + * @package OCA\Stackiq\Examples * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ class ContactpersoonServiceExample { /** diff --git a/lib/Exception/UnsupportedSbomFormatException.php b/lib/Exception/UnsupportedSbomFormatException.php index dac44031..9ae16c17 100644 --- a/lib/Exception/UnsupportedSbomFormatException.php +++ b/lib/Exception/UnsupportedSbomFormatException.php @@ -3,7 +3,7 @@ /** * UnsupportedSbomFormatException. * - * Thrown by {@see \OCA\SoftwareCatalog\Service\SbomParserService} when an + * Thrown by {@see \OCA\Stackiq\Service\SbomParserService} when an * uploaded document's `bomFormat`/`specVersion` (CycloneDX) or `spdxVersion` * (SPDX) is not one this app supports. Carries the offending format/version * in its message so the controller can surface a precise 422 rather than a @@ -11,11 +11,11 @@ * this is thrown (fail-fast, not a silent partial parse). * * @category Exception - * @package OCA\SoftwareCatalog\Exception + * @package OCA\Stackiq\Exception * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/sbom-import/spec.md#requirement-cyclonedx-sbom-files-are-parsed-into-a-normalized-component-list * @@ -25,7 +25,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Exception; +namespace OCA\Stackiq\Exception; /** * Thrown when an uploaded SBOM document's format/spec-version is not supported. diff --git a/lib/Portal/PortalContributionProvider.php b/lib/Portal/PortalContributionProvider.php index d3e68dfb..eb68b033 100644 --- a/lib/Portal/PortalContributionProvider.php +++ b/lib/Portal/PortalContributionProvider.php @@ -1,9 +1,9 @@ * @copyright 2026 Conduction B.V. @@ -42,10 +42,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Portal; +namespace OCA\Stackiq\Portal; /** - * Declares what an external portal subject may see in the Software Catalog. + * Declares what an external portal subject may see in Stackiq. * * The contribution is a declarative manifest (pure data — no I/O, no * callbacks). All subject identity (subjectRef, audience, organisation, trust) @@ -82,7 +82,7 @@ class PortalContributionProvider { /** * The audiences this provider contributes to (contract v2, preferred). * - * The registry probes for this method first. Software Catalog serves + * The registry probes for this method first. Stackiq serves * software suppliers (`vendor-org`, organisatie.type "Supplier") and the * municipalities/collaborations that consume that software (`participant-org`, * organisatie.type "Municipality" / "Collaboration" / "Community"). The two @@ -116,7 +116,7 @@ public function getAudience(): string { * * The subject array is server-derived by portaliq (subjectRef UUID, * audience, organisation, trust level low|substantial|high). Returns null - * for any audience Software Catalog does not serve (fail-closed; the registry + * for any audience Stackiq does not serve (fail-closed; the registry * already filters by audience, but a provider must not rely on that). This * wave declares READ collections only — no create-actions and no endpoint * actions (see design.md for the deferral rationale). @@ -159,7 +159,7 @@ public function getContribution(array $subject): ?array { */ private function vendorContribution(): array { return [ - 'label' => 'Software Catalog', + 'label' => 'Stackiq', 'collections' => [ [ 'id' => 'vendorDiensten', @@ -262,7 +262,7 @@ private function vendorContribution(): array { */ private function participantContribution(): array { return [ - 'label' => 'Software Catalog', + 'label' => 'Stackiq', 'collections' => [ [ 'id' => 'participantGebruik', diff --git a/lib/Repair/BackfillContractApprovalState.php b/lib/Repair/BackfillContractApprovalState.php index 8f85020e..73d4b36e 100644 --- a/lib/Repair/BackfillContractApprovalState.php +++ b/lib/Repair/BackfillContractApprovalState.php @@ -18,12 +18,12 @@ * named-argument convention as in MigrateContactsToNc. * * @category Repair - * @package OCA\SoftwareCatalog\Repair + * @package OCA\Stackiq\Repair * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/contract-decision-delegation/spec.md * @@ -33,10 +33,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Repair; +namespace OCA\Stackiq\Repair; -use OCA\SoftwareCatalog\Service\ContractApprovalService; -use OCA\SoftwareCatalog\Service\SettingsService; +use OCA\Stackiq\Service\ContractApprovalService; +use OCA\Stackiq\Service\SettingsService; use OCP\App\IAppManager; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Repair/InitializeSettings.php b/lib/Repair/InitializeSettings.php index ac4914de..9dad2e9a 100644 --- a/lib/Repair/InitializeSettings.php +++ b/lib/Repair/InitializeSettings.php @@ -1,23 +1,23 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Repair; +namespace OCA\Stackiq\Repair; -use OCA\SoftwareCatalog\AppInfo\Application; -use OCA\SoftwareCatalog\Service\SettingsService; +use OCA\Stackiq\AppInfo\Application; +use OCA\Stackiq\Service\SettingsService; use OCP\App\IAppManager; use OCP\IAppConfig; use OCP\Migration\IOutput; @@ -26,12 +26,12 @@ use Psr\Log\LoggerInterface; /** - * Repair step that initializes SoftwareCatalog settings on install/upgrade. + * Repair step that initializes Stackiq settings on install/upgrade. * * This runs only during app install or upgrade, not on every request. * * @category Repair - * @package OCA\SoftwareCatalog\Repair + * @package OCA\Stackiq\Repair * * @spec openspec/specs/repair-init/spec.md */ @@ -60,7 +60,7 @@ public function __construct( * @spec openspec/specs/repair-init/spec.md */ public function getName(): string { - return 'Initialize SoftwareCatalog settings'; + return 'Initialize Stackiq settings'; }//end getName() /** @@ -95,7 +95,7 @@ public function run(IOutput $output): void { } $output->info('Initializing settings for version ' . $currentAppVersion); - $this->logger->info('SoftwareCatalog repair: Starting initialization for version ' . $currentAppVersion); + $this->logger->info('Stackiq repair: Starting initialization for version ' . $currentAppVersion); // @spec openspec/specs/contract-administration/spec.md // Seed window defaults only when the admin has not set them, so @@ -145,18 +145,18 @@ public function run(IOutput $output): void { if (empty($result['errors']) === false) { foreach ($result['errors'] as $error) { $output->warning('Initialization warning: ' . $error); - $this->logger->warning('SoftwareCatalog repair: ' . $error); + $this->logger->warning('Stackiq repair: ' . $error); } } $output->info('Settings initialization completed'); - $this->logger->info('SoftwareCatalog repair: Initialization completed', ['result' => $result]); + $this->logger->info('Stackiq repair: Initialization completed', ['result' => $result]); } catch (\Exception $e) { // Still mark as initialized to prevent repeated failures. $currentAppVersion = $this->appManager->getAppVersion(Application::APP_ID); $this->config->setValueString(Application::APP_ID, 'last_initialized_version', $currentAppVersion); $output->warning('Settings initialization failed: ' . $e->getMessage()); - $this->logger->error('SoftwareCatalog repair: Initialization failed', ['exception' => $e->getMessage()]); + $this->logger->error('Stackiq repair: Initialization failed', ['exception' => $e->getMessage()]); }//end try $output->advance(1); diff --git a/lib/Repair/MigrateAppConfigKeys.php b/lib/Repair/MigrateAppConfigKeys.php new file mode 100644 index 00000000..83e8691e --- /dev/null +++ b/lib/Repair/MigrateAppConfigKeys.php @@ -0,0 +1,230 @@ +` and `` and MUST stay + * there. `InitializeSettings` writes app config itself; if it ran first, every + * key it touched would look "already present" here and the operator's real + * value would stay stranded in the old namespace forever. + * + * All OCP service calls use POSITIONAL arguments (named args are FATAL on + * `occ upgrade`). + * + * @category Repair + * @package OCA\Stackiq\Repair + * @author Conduction b.v. + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @version GIT: + * @link https://github.com/ConductionNL/stackiq + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-app-config-survives-the-rename + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Stackiq\Repair; + +use OCA\Stackiq\AppInfo\Application; +use OCP\IAppConfig; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; +use Psr\Log\LoggerInterface; +use Throwable; + +/** + * Copies app config from the legacy `stackiq` app id to `stackiq`. + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-app-config-survives-the-rename + */ +class MigrateAppConfigKeys implements IRepairStep { + /** + * The app id every stored row was written under before the rename. + */ + public const LEGACY_APP_ID = 'softwarecatalog'; + + /** + * Keys Nextcloud owns in every app's namespace. These MUST NOT be copied. + * + * `enabled` is the dangerous one. `AppManager::enableApp()` writes it as + * type MIXED; copying it with `setValueString()` stores it as STRING, and + * the next `occ app:enable` then fails permanently with + * `AppConfigTypeConflictException` — a conflict that is hit BEFORE the app + * can run anything that would repair it. `installed_version` and `types` + * are Nextcloud's own bookkeeping for the new id and are already correct. + */ + private const RESERVED_KEYS = [ + 'enabled', + 'installed_version', + 'types', + ]; + + /** + * Constructor. + * + * @param IAppConfig $appConfig The typed app config service. + * @param LoggerInterface $logger The logger. + */ + public function __construct( + private readonly IAppConfig $appConfig, + private readonly LoggerInterface $logger, + ) { + }//end __construct() + + /** + * Returns the name of this repair step. + * + * @return string The repair step name. + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-app-config-survives-the-rename + */ + public function getName(): string { + return 'Migrate app config from the stackiq app id to stackiq'; + }//end getName() + + /** + * Copy every non-reserved app config key from the legacy app id. + * + * Both the READS and the WRITE sit inside the try. This step runs under + * `` — the only hook that fires on the fresh install an app-id + * rename performs — so an escaping throw aborts the install and the app + * never enables at all. A config key that fails to copy is a reverted + * setting; a failed install is no app. + * + * @param IOutput $output The output interface for progress reporting. + * + * @return void + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-app-config-survives-the-rename + */ + public function run(IOutput $output): void { + try { + // Exhaustive enumeration. getKeys() lists every key stored under the + // old app id regardless of value — the alternative shapes + // (searchValues, getUsersForUserValue) all match on a VALUE, so over + // an open value set they migrate nothing and report success. + $keys = $this->appConfig->getKeys(self::LEGACY_APP_ID); + + // Values come from getAllValues() rather than the typed getters + // because it returns each row in its STORED type without asserting + // one. getValueString() on a key stored as MIXED or INT raises + // AppConfigTypeConflictException, which would abort the whole copy + // on the first typed key it met. + $values = $this->appConfig->getAllValues(self::LEGACY_APP_ID); + + $copied = 0; + $skipped = 0; + + foreach ($keys as $key) { + if (in_array($key, self::RESERVED_KEYS, true) === true) { + $skipped++; + continue; + } + + // Never clobber a value the new namespace already holds — either + // a previous run copied it, or an admin has since changed it. + if ($this->appConfig->hasKey(Application::APP_ID, $key) === true) { + $skipped++; + continue; + } + + if (array_key_exists($key, $values) === false) { + $skipped++; + continue; + } + + if ($this->copyValue(key: $key, value: $values[$key]) === true) { + $copied++; + continue; + } + + $skipped++; + } + + $output->info( + sprintf( + 'Stackiq: migrated %d app config key(s) from "%s" (skipped %d)', + $copied, + self::LEGACY_APP_ID, + $skipped + ) + ); + } catch (Throwable $e) { + // Swallowed deliberately — see the docblock. Logged at error level so + // the reverted-settings symptom has a cause to find. + $this->logger->error( + 'Stackiq: failed to migrate app config from the legacy app id: ' . $e->getMessage(), + [ + 'app' => Application::APP_ID, + 'exception' => $e, + ] + ); + $output->warning('Stackiq: app config migration failed; see the log. Settings may have reverted to defaults.'); + }//end try + }//end run() + + /** + * Write one legacy value into the new namespace in its own type. + * + * Empty strings and empty arrays are treated as "nothing stored" and are + * not copied — an empty value is indistinguishable from the default every + * reader already supplies, so copying it adds a row and changes nothing. + * Scalars are copied as-is: `false` and `0` are real, chosen values. + * + * @param string $key The config key. + * @param mixed $value The value as stored under the legacy app id. + * + * @return bool True when a value was written. + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-app-config-survives-the-rename + */ + protected function copyValue(string $key, mixed $value): bool { + if (is_bool($value) === true) { + $this->appConfig->setValueBool(Application::APP_ID, $key, $value); + return true; + } + + if (is_int($value) === true) { + $this->appConfig->setValueInt(Application::APP_ID, $key, $value); + return true; + } + + if (is_float($value) === true) { + $this->appConfig->setValueFloat(Application::APP_ID, $key, $value); + return true; + } + + if (is_array($value) === true) { + if ($value === []) { + return false; + } + + $this->appConfig->setValueArray(Application::APP_ID, $key, $value); + return true; + } + + $string = (string)$value; + if ($string === '') { + return false; + } + + $this->appConfig->setValueString(Application::APP_ID, $key, $string); + return true; + }//end copyValue() +}//end class diff --git a/lib/Repair/MigrateBackgroundJobClasses.php b/lib/Repair/MigrateBackgroundJobClasses.php new file mode 100644 index 00000000..09e1fc10 --- /dev/null +++ b/lib/Repair/MigrateBackgroundJobClasses.php @@ -0,0 +1,145 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @version GIT: + * @link https://github.com/ConductionNL/stackiq + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-background-job-classes-survive-the-rename + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Stackiq\Repair; + +use OCA\Stackiq\AppInfo\Application; +use OCP\BackgroundJob\IJobList; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; +use Psr\Log\LoggerInterface; +use Throwable; + +/** + * Removes background job registrations left behind by the namespace rename. + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-background-job-classes-survive-the-rename + */ +class MigrateBackgroundJobClasses implements IRepairStep { + /** + * The exact job class strings written to `oc_jobs` before the rename. + * + * Written out in full rather than derived from the current class names, + * so that a later namespace change cannot silently widen what this step + * deletes. These four are the complete `` list as it stood + * in `appinfo/info.xml` before the rename. + */ + public const LEGACY_JOB_CLASSES = [ + 'OCA\SoftwareCatalog\BackgroundJob\OrganizationContactSyncJob', + 'OCA\SoftwareCatalog\BackgroundJob\ContractStatusJob', + 'OCA\SoftwareCatalog\BackgroundJob\FederationSyncJob', + 'OCA\SoftwareCatalog\BackgroundJob\EolSyncJob', + ]; + + /** + * Constructor. + * + * @param IJobList $jobList The background job list. + * @param LoggerInterface $logger The logger. + */ + public function __construct( + private readonly IJobList $jobList, + private readonly LoggerInterface $logger, + ) { + }//end __construct() + + /** + * Returns the name of this repair step. + * + * @return string The repair step name. + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-background-job-classes-survive-the-rename + */ + public function getName(): string { + return 'Deregister background jobs orphaned by the OCA\\SoftwareCatalog namespace rename'; + }//end getName() + + /** + * Remove every legacy job registration. + * + * The whole body sits inside the try. This step runs under `` — + * the only hook that fires on the fresh install an app-id rename performs — + * so an escaping throw aborts the install and the app never enables at all. + * + * @param IOutput $output The output interface for progress reporting. + * + * @return void + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-background-job-classes-survive-the-rename + */ + public function run(IOutput $output): void { + try { + $removed = 0; + + foreach (self::LEGACY_JOB_CLASSES as $legacyClass) { + // The remove() call is a no-op when the row is absent, so has() is + // only an accounting call — it keeps the reported count honest on a + // re-run rather than claiming work that did not happen. + // PHPStan wants a class-string here, which this method can + // never supply: the whole point is to deregister jobs whose class + // NO LONGER EXISTS after the namespace rename. A loadable + // class-string would mean there was nothing to clean up. The + // stored rows are matched by their literal class name, which is + // exactly what IJobList compares against. + // @phpstan-ignore argument.type + if ($this->jobList->has($legacyClass, null) === false) { + continue; + } + + // @phpstan-ignore argument.type + $this->jobList->remove($legacyClass, null); + $removed++; + } + + $output->info( + sprintf('Stackiq: deregistered %d orphaned background job(s) from the legacy namespace', $removed) + ); + } catch (Throwable $e) { + // Swallowed deliberately — see the docblock. + $this->logger->error( + 'Stackiq: failed to deregister legacy background jobs: ' . $e->getMessage(), + [ + 'app' => Application::APP_ID, + 'exception' => $e, + ] + ); + $output->warning('Stackiq: legacy background job cleanup failed; see the log.'); + }//end try + }//end run() +}//end class diff --git a/lib/Repair/MigrateContactsToNc.php b/lib/Repair/MigrateContactsToNc.php index 3821e522..663accdc 100644 --- a/lib/Repair/MigrateContactsToNc.php +++ b/lib/Repair/MigrateContactsToNc.php @@ -1,7 +1,7 @@ * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/softwarecatalog-contacts-to-nc/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Repair; +namespace OCA\Stackiq\Repair; -use OCA\SoftwareCatalog\AppInfo\Application; -use OCA\SoftwareCatalog\Service\SettingsService; -use OCA\SoftwareCatalog\Service\SoftwareCatalogContactSyncService; +use OCA\Stackiq\AppInfo\Application; +use OCA\Stackiq\Service\SettingsService; +use OCA\Stackiq\Service\StackiqContactSyncService; use OCP\App\IAppManager; use OCP\IAppConfig; use OCP\Migration\IOutput; @@ -44,11 +44,11 @@ * Idempotent, fail-safe migration of identity to Nextcloud Contacts. * * @category Repair - * @package OCA\SoftwareCatalog\Repair + * @package OCA\Stackiq\Repair * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/softwarecatalog-contacts-to-nc/spec.md */ @@ -69,7 +69,7 @@ class MigrateContactsToNc implements IRepairStep { * * @param IAppManager $appManager The app manager. * @param SettingsService $settingsService The settings service (register/schema id resolution). - * @param SoftwareCatalogContactSyncService $contactSync The contacts bridge. + * @param StackiqContactSyncService $contactSync The contacts bridge. * @param IAppConfig $appConfig The app config (convergence marker). * @param LoggerInterface $logger The logger. * @@ -78,7 +78,7 @@ class MigrateContactsToNc implements IRepairStep { public function __construct( private readonly IAppManager $appManager, private readonly SettingsService $settingsService, - private readonly SoftwareCatalogContactSyncService $contactSync, + private readonly StackiqContactSyncService $contactSync, private readonly IAppConfig $appConfig, private readonly LoggerInterface $logger, ) { @@ -92,7 +92,7 @@ public function __construct( * @spec openspec/specs/softwarecatalog-contacts-to-nc/spec.md */ public function getName(): string { - return 'Migrate SoftwareCatalog contacts/organisations to the Nextcloud addressbook'; + return 'Migrate Stackiq contacts/organisations to the Nextcloud addressbook'; }//end getName() /** diff --git a/lib/Repair/MigrateUserPreferences.php b/lib/Repair/MigrateUserPreferences.php new file mode 100644 index 00000000..96d89639 --- /dev/null +++ b/lib/Repair/MigrateUserPreferences.php @@ -0,0 +1,195 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @version GIT: + * @link https://github.com/ConductionNL/stackiq + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-user-preferences-survive-the-rename + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\Stackiq\Repair; + +use Closure; +use OCA\Stackiq\AppInfo\Application; +use OCP\IConfig; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; +use Psr\Log\LoggerInterface; +use Throwable; + +/** + * Copies per-user preferences from the legacy `stackiq` app id to `stackiq`. + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-user-preferences-survive-the-rename + */ +class MigrateUserPreferences implements IRepairStep { + /** + * The app id every stored preference was written under before the rename. + */ + public const LEGACY_APP_ID = 'softwarecatalog'; + + /** + * Number of preference values copied during the current run. + * + * @var int + */ + private int $copied = 0; + + /** + * Number of users that carried at least one legacy preference. + * + * @var int + */ + private int $users = 0; + + /** + * Constructor. + * + * @param IConfig $config The user config service. + * @param IUserManager $userManager The user manager. + * @param LoggerInterface $logger The logger. + */ + public function __construct( + private readonly IConfig $config, + private readonly IUserManager $userManager, + private readonly LoggerInterface $logger, + ) { + }//end __construct() + + /** + * Returns the name of this repair step. + * + * @return string The repair step name. + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-user-preferences-survive-the-rename + */ + public function getName(): string { + return 'Migrate user preferences from the stackiq app id to stackiq'; + }//end getName() + + /** + * Copy every legacy preference for every seen user. + * + * Both the READS and the WRITES sit inside the try. This step runs under + * `` — the only hook that fires on the fresh install an app-id + * rename performs — so an escaping throw aborts the install and the app + * never enables at all. + * + * @param IOutput $output The output interface for progress reporting. + * + * @return void + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-user-preferences-survive-the-rename + */ + public function run(IOutput $output): void { + $this->copied = 0; + $this->users = 0; + + try { + // The callback must return bool|null, not void: IUserManager treats a + // `false` return as "stop iterating", so null means "keep going". + // A void closure does not satisfy that contract. + $this->userManager->callForSeenUsers( + function (IUser $user): ?bool { + $this->migrateUser(user: $user); + return null; + } + ); + + $output->info( + sprintf( + 'Stackiq: migrated %d user preference value(s) for %d user(s) from "%s"', + $this->copied, + $this->users, + self::LEGACY_APP_ID + ) + ); + } catch (Throwable $e) { + // Swallowed deliberately — see the docblock. + $this->logger->error( + 'Stackiq: failed to migrate user preferences from the legacy app id: ' . $e->getMessage(), + [ + 'app' => Application::APP_ID, + 'exception' => $e, + ] + ); + $output->warning('Stackiq: user preference migration failed; see the log. Users may see default view settings.'); + }//end try + }//end run() + + /** + * Copy one user's legacy preferences into the new namespace. + * + * @param IUser $user The user to migrate. + * + * @return void + * + * @spec openspec/changes/rename-app-id-to-stackiq/specs/app-id-rename/spec.md#requirement-stored-user-preferences-survive-the-rename + */ + protected function migrateUser(IUser $user): void { + $userId = $user->getUID(); + + // Exhaustive per-user enumeration. getUserKeys() lists the keys this + // user actually holds under the old app id — it needs no value to match, + // which is exactly why getUsersForUserValue() is unusable here. + $keys = $this->config->getUserKeys($userId, self::LEGACY_APP_ID); + if ($keys === []) { + return; + } + + $touched = false; + + foreach ($keys as $key) { + $legacy = $this->config->getUserValue($userId, self::LEGACY_APP_ID, $key, ''); + if ($legacy === '') { + continue; + } + + // Never clobber a value the new namespace already holds. + $current = $this->config->getUserValue($userId, Application::APP_ID, $key, ''); + if ($current !== '') { + continue; + } + + $this->config->setUserValue($userId, Application::APP_ID, $key, $legacy); + $this->copied++; + $touched = true; + } + + if ($touched === true) { + $this->users++; + } + }//end migrateUser() +}//end class diff --git a/lib/Repair/RenameDutchCatalogColumns.php b/lib/Repair/RenameDutchCatalogColumns.php index 42cd013b..b3d78e92 100644 --- a/lib/Repair/RenameDutchCatalogColumns.php +++ b/lib/Repair/RenameDutchCatalogColumns.php @@ -1,7 +1,7 @@ * @copyright 2026 Conduction B.V. @@ -103,7 +103,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Repair; +namespace OCA\Stackiq\Repair; use OCP\DB\Exception; use OCP\IDBConnection; @@ -122,7 +122,7 @@ class RenameDutchCatalogColumns implements IRepairStep { * * @var string */ - private const REGISTER_SLUG = 'softwarecatalog'; + private const REGISTER_SLUG = 'stackiq'; /** * Schema slugs holding externally-standardised field names, which are @@ -434,7 +434,7 @@ private function migrateTable(string $table, array $declared): array { * Read from `oc_openregister_schemas.properties`, which is the shape * MagicMapper materialises columns from — verified first-hand against a live * instance rather than inferred: the column is `json`, `jsonb_typeof` is - * `object` for all 21 softwarecatalog schemas, and it is keyed by the + * `object` for all 21 stackiq schemas, and it is keyed by the * camelCase property name (`properties::jsonb ? 'name'` is true on exactly * the schemas the register JSON declares `naam` on). * diff --git a/lib/Repair/RenameDutchCatalogDecisions.php b/lib/Repair/RenameDutchCatalogDecisions.php index 5ad22487..fe8cba10 100644 --- a/lib/Repair/RenameDutchCatalogDecisions.php +++ b/lib/Repair/RenameDutchCatalogDecisions.php @@ -12,7 +12,7 @@ * was already sitting on before the candidate-target support was added. * * @category Repair - * @package OCA\\SoftwareCatalog\\Repair + * @package OCA\\Stackiq\\Repair * @author Conduction B.V. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -24,13 +24,13 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Repair; +namespace OCA\Stackiq\Repair; /** * Pure predicates for the Dutch-to-English column migration. * * @category Repair - * @package OCA\\SoftwareCatalog\\Repair + * @package OCA\\Stackiq\\Repair * @author Conduction B.V. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -70,7 +70,7 @@ public function sanitizeColumnName(string $name): string { /** * Whether moving `$old` to `$new` is safe for a schema declaring `$declared`. * - * This is the softwarecatalog#492 guard, and it is deliberately BOTH halves: + * This is the stackiq#492 guard, and it is deliberately BOTH halves: * * - the destination MUST be declared — otherwise the data lands in a * column nothing reads, and MagicMapper will re-add the Dutch one empty; @@ -139,7 +139,7 @@ public function firstSafeTarget(string $old, array $candidates, array $declared) * issuing an UPDATE against a missing column is an error rather than a no-op. * * @param array> $valueMap Property => old => new. - * @param array $columns Columns the table has. + * @param array $columns Columns the table has. * * @return array */ diff --git a/lib/Repair/RenameDutchCatalogValues.php b/lib/Repair/RenameDutchCatalogValues.php index 03e41d44..3e25caae 100644 --- a/lib/Repair/RenameDutchCatalogValues.php +++ b/lib/Repair/RenameDutchCatalogValues.php @@ -18,7 +18,7 @@ * Idempotent: an already-migrated row simply matches no WHERE clause. * * @category Repair - * @package OCA\SoftwareCatalog\Repair + * @package OCA\Stackiq\Repair * @author Conduction B.V. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -30,7 +30,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Repair; +namespace OCA\Stackiq\Repair; use OCP\DB\Exception; use OCP\IDBConnection; @@ -138,9 +138,9 @@ class RenameDutchCatalogValues implements IRepairStep { /** * Constructor. * - * @param IDBConnection $db Database connection. - * @param LoggerInterface $logger Logger. - * @param RenameDutchCatalogDecisions $decisions Column-name predicates. + * @param IDBConnection $db Database connection. + * @param LoggerInterface $logger Logger. + * @param RenameDutchCatalogDecisions $decisions Column-name predicates. */ public function __construct( private readonly IDBConnection $db, @@ -155,7 +155,7 @@ public function __construct( * @return string */ public function getName(): string { - return 'Translate stored Dutch SoftwareCatalog enum values'; + return 'Translate stored Dutch Stackiq enum values'; }//end getName() /** @@ -164,11 +164,13 @@ public function getName(): string { * @param IOutput $output Repair output. * * @return void + * + * @spec openspec/specs/english-vocabulary-migration/spec.md#requirement-the-migration-is-non-destructive-and-idempotent */ public function run(IOutput $output): void { $tables = $this->shardTables(); if ($tables === []) { - $output->info('RenameDutchCatalogValues: no SoftwareCatalog shard tables on this install; nothing to do.'); + $output->info('RenameDutchCatalogValues: no Stackiq shard tables on this install; nothing to do.'); return; } @@ -195,10 +197,10 @@ public function run(IOutput $output): void { /** * Rewrite one value in one column. * - * @param string $table Shard table. + * @param string $table Shard table. * @param string $column Column name. - * @param string $old Stored Dutch value. - * @param string $new English replacement. + * @param string $old Stored Dutch value. + * @param string $new English replacement. * * @return int Rows affected. */ diff --git a/lib/Repair/RenameDutchSchemaSlugDecisions.php b/lib/Repair/RenameDutchSchemaSlugDecisions.php index 9fadb66a..5e31f17a 100644 --- a/lib/Repair/RenameDutchSchemaSlugDecisions.php +++ b/lib/Repair/RenameDutchSchemaSlugDecisions.php @@ -13,7 +13,7 @@ * can be decided before touching it is decided here. * * @category Repair - * @package OCA\SoftwareCatalog\Repair + * @package OCA\Stackiq\Repair * @author Conduction B.V. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -25,7 +25,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Repair; +namespace OCA\Stackiq\Repair; /** * Pure predicates for the Dutch-to-English schema slug migration. @@ -44,8 +44,8 @@ class RenameDutchSchemaSlugDecisions { * is visible to the collision check of a later one — otherwise two entries * targeting the same name would both look safe. * - * @param array $map Old slug => new slug. - * @param array $existing Slugs currently present. + * @param array $map Old slug => new slug. + * @param array $existing Slugs currently present. * * @return array{renames: array, refused: array} */ @@ -130,7 +130,7 @@ public function schemaIdsFrom(array $rows): array { * would make an empty schema look occupied and refuse a safe merge. * * @param string $tableName The candidate table name. - * @param int $schemaId The schema id. + * @param int $schemaId The schema id. * * @return bool True when the table belongs to that schema. */ diff --git a/lib/Repair/RenameDutchSchemaSlugs.php b/lib/Repair/RenameDutchSchemaSlugs.php index 3882b377..0182661b 100644 --- a/lib/Repair/RenameDutchSchemaSlugs.php +++ b/lib/Repair/RenameDutchSchemaSlugs.php @@ -28,7 +28,7 @@ * Dutch keys, so resolution is unaffected by this step. * * @category Repair - * @package OCA\SoftwareCatalog\Repair + * @package OCA\Stackiq\Repair * @author Conduction B.V. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -40,7 +40,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Repair; +namespace OCA\Stackiq\Repair; use OCP\DB\Exception; use OCP\IDBConnection; @@ -101,8 +101,8 @@ class RenameDutchSchemaSlugs implements IRepairStep { /** * Constructor. * - * @param IDBConnection $db Database connection. - * @param LoggerInterface $logger Logger. + * @param IDBConnection $db Database connection. + * @param LoggerInterface $logger Logger. * @param RenameDutchSchemaSlugDecisions $decisions The pure predicates. */ public function __construct( @@ -118,7 +118,7 @@ public function __construct( * @return string */ public function getName(): string { - return 'Rename Dutch SoftwareCatalog schema slugs'; + return 'Rename Dutch Stackiq schema slugs'; }//end getName() /** @@ -127,11 +127,13 @@ public function getName(): string { * @param IOutput $output Repair output. * * @return void + * + * @spec openspec/specs/english-vocabulary-migration/spec.md#requirement-renaming-a-stored-property-ships-a-data-migration */ public function run(IOutput $output): void { $schemaIds = $this->inScopeSchemaIds(); if ($schemaIds === []) { - $output->info('RenameDutchSchemaSlugs: no SoftwareCatalog registers on this install; nothing to do.'); + $output->info('RenameDutchSchemaSlugs: no Stackiq registers on this install; nothing to do.'); return; } @@ -180,7 +182,7 @@ public function run(IOutput $output): void { * the fact. So it refuses, loudly, and leaves both schemas alone. * * @param array $schemaIds Schema ids in scope. - * @param IOutput $output Repair output. + * @param IOutput $output Repair output. * * @return void */ @@ -365,8 +367,8 @@ private function slugsOf(array $schemaIds): array { /** * Rename one slug, scoped to this app's schemas. * - * @param string $old Current slug. - * @param string $new Replacement slug. + * @param string $old Current slug. + * @param string $new Replacement slug. * @param array $schemaIds Schema ids in scope. * * @return bool True when the row was updated. diff --git a/lib/Sections/SoftwareCatalogAdmin.php b/lib/Sections/StackiqAdmin.php similarity index 77% rename from lib/Sections/SoftwareCatalogAdmin.php rename to lib/Sections/StackiqAdmin.php index 5e65a48f..def9678d 100644 --- a/lib/Sections/SoftwareCatalogAdmin.php +++ b/lib/Sections/StackiqAdmin.php @@ -1,24 +1,24 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ -namespace OCA\SoftwareCatalog\Sections; +namespace OCA\Stackiq\Sections; use OCP\IL10N; use OCP\IURLGenerator; use OCP\Settings\IIconSection; -class SoftwareCatalogAdmin implements IIconSection { +class StackiqAdmin implements IIconSection { /** * The localization service. @@ -35,7 +35,7 @@ class SoftwareCatalogAdmin implements IIconSection { private IURLGenerator $urlGenerator; /** - * Constructor for SoftwareCatalogAdmin section. + * Constructor for StackiqAdmin section. * * @param IL10N $l10n The localization service * @param IURLGenerator $urlGenerator The URL generator service @@ -52,7 +52,7 @@ public function __construct(IL10N $l10n, IURLGenerator $urlGenerator) { */ public function getIcon(): string { // phpcs:ignore -- named parameters unsafe for Nextcloud core methods (param names vary by NC version) - return $this->urlGenerator->imagePath('softwarecatalog', 'app-dark.svg'); + return $this->urlGenerator->imagePath('stackiq', 'app-dark.svg'); }//end getIcon() /** @@ -61,7 +61,7 @@ public function getIcon(): string { * @return string The section ID */ public function getID(): string { - return 'softwarecatalog'; + return 'stackiq'; }//end getID() /** @@ -70,7 +70,7 @@ public function getID(): string { * @return string The translated section name */ public function getName(): string { - return $this->l10n->t('Software Catalog'); + return $this->l10n->t('Stackiq'); }//end getName() /** diff --git a/lib/Service/AanbodService.php b/lib/Service/AanbodService.php index 68bddf92..1842300b 100644 --- a/lib/Service/AanbodService.php +++ b/lib/Service/AanbodService.php @@ -1,26 +1,26 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use Exception; use OCA\OpenRegister\Contract\ObjectServiceInterface; @@ -38,12 +38,12 @@ * afnemer (consumer) or aanbieder (provider), and for accepting or denying these offers. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity) diff --git a/lib/Service/AangebodenGebruik/GebruikBulkHandler.php b/lib/Service/AangebodenGebruik/GebruikBulkHandler.php index 76dcf196..9661df92 100644 --- a/lib/Service/AangebodenGebruik/GebruikBulkHandler.php +++ b/lib/Service/AangebodenGebruik/GebruikBulkHandler.php @@ -1,17 +1,17 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/method-decomposition/tasks.md#task-7 * @@ -21,7 +21,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\AangebodenGebruik; +namespace OCA\Stackiq\Service\AangebodenGebruik; use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Log\LoggerInterface; diff --git a/lib/Service/AangebodenGebruikService.php b/lib/Service/AangebodenGebruikService.php index ac760da7..b3006f95 100644 --- a/lib/Service/AangebodenGebruikService.php +++ b/lib/Service/AangebodenGebruikService.php @@ -1,24 +1,24 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use Exception; use OCA\OpenRegister\Contract\ObjectServiceInterface; @@ -36,12 +36,12 @@ * (participants) array, and for updating the @self property of gebruiks objects. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @SuppressWarnings(PHPMD.ExcessiveClassLength) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) @@ -241,7 +241,7 @@ public function getGebruiksWhereAfnemer(array $options = []): array { // Build next/previous links. $nextLink = null; $prevLink = null; - $consumerPath = '/index.php/apps/softwarecatalog/api/aangeboden-gebruik/afnemer'; + $consumerPath = '/index.php/apps/stackiq/api/aangeboden-gebruik/afnemer'; if ($currentPage < $totalPages) { $nextPage = $currentPage + 1; $nextLink = "{$consumerPath}?_limit={$requestedLimit}&_source=database&page={$nextPage}"; diff --git a/lib/Service/ArchiMate/ArchiMateContext.php b/lib/Service/ArchiMate/ArchiMateContext.php index e31edf57..ea5b435b 100644 --- a/lib/Service/ArchiMate/ArchiMateContext.php +++ b/lib/Service/ArchiMate/ArchiMateContext.php @@ -1,17 +1,17 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/method-decomposition/tasks.md#task-4 * @@ -21,10 +21,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\ArchiMate; +namespace OCA\Stackiq\Service\ArchiMate; use OCA\OpenRegister\Contract\ObjectServiceInterface; -use OCA\SoftwareCatalog\Service\SettingsService; +use OCA\Stackiq\Service\SettingsService; use Psr\Log\LoggerInterface; /** @@ -41,7 +41,7 @@ class ArchiMateContext { * Constructor. * * @param ObjectServiceInterface $objectService The OpenRegister object service. - * @param SettingsService $settingsService The SoftwareCatalog settings service. + * @param SettingsService $settingsService The Stackiq settings service. * @param LoggerInterface $logger The application logger. * * @spec openspec/changes/method-decomposition/tasks.md#task-4 diff --git a/lib/Service/ArchiMateExportService.php b/lib/Service/ArchiMateExportService.php index 38d2be00..ac365400 100644 --- a/lib/Service/ArchiMateExportService.php +++ b/lib/Service/ArchiMateExportService.php @@ -4,7 +4,7 @@ * ArchiMate Export Service. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -14,19 +14,19 @@ */ /** - * ArchiMate Export Service for the SoftwareCatalog app + * ArchiMate Export Service for the Stackiq app * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use Psr\Log\LoggerInterface; @@ -2878,7 +2878,7 @@ private function getViewName(array $viewData): string { }//end getViewName() /** - * Add Bron=Softwarecatalogus property to an XML data array. + * Add Bron=Stackiq property to an XML data array. * * @param array $data The data array. * @param string $sourcePropDefId The Bron property definition ID. @@ -2888,7 +2888,7 @@ private function getViewName(array $viewData): string { private function addSourceProperty(array $data, string $sourcePropDefId): array { $sourceProp = [ '_propertyDefinitionRef' => $sourcePropDefId, - 'value' => ['_value' => 'Softwarecatalogus'], + 'value' => ['_value' => 'Stackiq'], ]; if (isset($data['properties']) === false) { @@ -3071,7 +3071,7 @@ private function buildSwcOrganizationFolders( } $folders[] = [ - 'label' => ['_value' => 'Gebruikt (Softwarecatalogus)'], + 'label' => ['_value' => 'Gebruikt (Stackiq)'], 'items' => $items, ]; } @@ -3083,7 +3083,7 @@ private function buildSwcOrganizationFolders( } $folders[] = [ - 'label' => ['_value' => 'Deelnames (Softwarecatalogus)'], + 'label' => ['_value' => 'Deelnames (Stackiq)'], 'items' => $items, ]; } @@ -3096,7 +3096,7 @@ private function buildSwcOrganizationFolders( } $folders[] = [ - 'label' => ['_value' => 'Relaties (Softwarecatalogus)'], + 'label' => ['_value' => 'Relaties (Stackiq)'], 'items' => $relItems, ]; } @@ -3108,7 +3108,7 @@ private function buildSwcOrganizationFolders( } $folders[] = [ - 'label' => ['_value' => 'Views (Softwarecatalogus)'], + 'label' => ['_value' => 'Views (Stackiq)'], 'items' => $viewItems, ]; } @@ -3146,7 +3146,7 @@ private function assembleOrganizationXml( $xml = $this->createCleanArchiMateXml(modelMetadata: $modelMetadata); // Override model name. - $modelName = 'Softwarecatalogus ' . $orgName; + $modelName = 'Stackiq ' . $orgName; // Remove existing name children and add new one. foreach ($xml->children() as $child) { if ($child->getName() === 'name') { @@ -3203,7 +3203,7 @@ private function assembleOrganizationXml( $propsEl = $elNode->addChild('properties'); $propEl = $propsEl->addChild('property'); $propEl->addAttribute('propertyDefinitionRef', $appEl['bronPropDefId']); - $propEl->addChild('value', 'Softwarecatalogus'); + $propEl->addChild('value', 'Stackiq'); } // --- Relationships section ---. @@ -3235,7 +3235,7 @@ private function assembleOrganizationXml( $propsEl = $relNode->addChild('properties'); $propEl = $propsEl->addChild('property'); $propEl->addAttribute('propertyDefinitionRef', $rel['bronPropDefId']); - $propEl->addChild('value', 'Softwarecatalogus'); + $propEl->addChild('value', 'Stackiq'); } // --- Property Definitions section ---. diff --git a/lib/Service/ArchiMateImportService.php b/lib/Service/ArchiMateImportService.php index d5e41407..a1a4a157 100644 --- a/lib/Service/ArchiMateImportService.php +++ b/lib/Service/ArchiMateImportService.php @@ -1,24 +1,24 @@ + * @package OCA\Stackiq\Service + * @author Stackiq Team * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://github.com/nextcloud/softwarecatalog + * @link https://github.com/nextcloud/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; @@ -43,11 +43,11 @@ * 5. Save objects using ObjectService::saveObjects * * @category Service - * @package OCA\SoftwareCatalog\Service - * @author SoftwareCatalog Team + * @package OCA\Stackiq\Service + * @author Stackiq Team * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://github.com/nextcloud/softwarecatalog + * @link https://github.com/nextcloud/stackiq * * @SuppressWarnings(PHPMD.ExcessiveClassLength) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) @@ -1960,7 +1960,7 @@ private function getCurrentOrganisation(): string { * @spec openspec/specs/archimate-import/spec.md */ private function resolveConfiguredId(string $key): ?string { - $value = $this->config->getValueString('softwarecatalog', $key, ''); + $value = $this->config->getValueString('stackiq', $key, ''); if (trim($value) === '') { $this->logger->warning( 'ArchiMate configuration is incomplete — this id is not configured, so it is omitted rather than passed on as an empty string', @@ -1984,7 +1984,7 @@ public function getAmefConfig(): array { try { // Get configuration from app config using the correct method. - $config = $this->config->getValueString('softwarecatalog', 'amef_config', '{}'); + $config = $this->config->getValueString('stackiq', 'amef_config', '{}'); $decoded = json_decode($config, true); if (is_array($decoded) === false) { @@ -2041,9 +2041,9 @@ private function getAmefRegisterId(): ?int { // Fallback to legacy individual app config keys if not present in JSON. if ($rawRegisterId === null || $rawRegisterId === '') { - $rawRegisterId = $this->config->getValueString('softwarecatalog', 'amef_register_id', ''); - if ($this->config->getValueString('softwarecatalog', 'amef_register', '') !== '') { - $rawRegisterId = $this->config->getValueString('softwarecatalog', 'amef_register', ''); + $rawRegisterId = $this->config->getValueString('stackiq', 'amef_register_id', ''); + if ($this->config->getValueString('stackiq', 'amef_register', '') !== '') { + $rawRegisterId = $this->config->getValueString('stackiq', 'amef_register', ''); } } @@ -2113,9 +2113,9 @@ private function getAmefSchemaIdForType(string $archiMateType): ?int { // Fallback to legacy individual app config keys if not present in JSON. foreach ($candidates as $key) { - $raw = $this->config->getValueString('softwarecatalog', $key, ''); - if ($this->config->getValueString('softwarecatalog', 'amef_' . $key, '') !== '') { - $raw = $this->config->getValueString('softwarecatalog', 'amef_' . $key, ''); + $raw = $this->config->getValueString('stackiq', $key, ''); + if ($this->config->getValueString('stackiq', 'amef_' . $key, '') !== '') { + $raw = $this->config->getValueString('stackiq', 'amef_' . $key, ''); } if ($raw !== '' && is_numeric((string)$raw) === true) { diff --git a/lib/Service/ArchiMateService.php b/lib/Service/ArchiMateService.php index d9376a5d..e08c4617 100644 --- a/lib/Service/ArchiMateService.php +++ b/lib/Service/ArchiMateService.php @@ -1,25 +1,25 @@ + * @package OCA\Stackiq\Service + * @author Stackiq Team * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://github.com/nextcloud/softwarecatalog + * @link https://github.com/nextcloud/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Service\ObjectService; @@ -39,11 +39,11 @@ * 3. Export: Reconstruct exact XML from stored JSON blobs * * @category Service - * @package OCA\SoftwareCatalog\Service - * @author SoftwareCatalog Team + * @package OCA\Stackiq\Service + * @author Stackiq Team * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://github.com/nextcloud/softwarecatalog + * @link https://github.com/nextcloud/stackiq * * @SuppressWarnings(PHPMD.ExcessiveClassLength) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) @@ -475,8 +475,8 @@ public function exportOrgArchiMate(string $organizationUuid, array $options = [] $options ); - // Generate file name: DD-MM-YYYY_Softwarecatalogus_AMEFF_export_OrgName.xml. - $fileName = date('d-m-Y') . '_Softwarecatalogus_AMEFF_export_' . str_replace(' ', '_', $orgName) . '.xml'; + // Generate file name: DD-MM-YYYY_Stackiq_AMEFF_export_OrgName.xml. + $fileName = date('d-m-Y') . '_Stackiq_AMEFF_export_' . str_replace(' ', '_', $orgName) . '.xml'; return [ 'success' => true, @@ -1392,7 +1392,7 @@ private function validateRequiredConfiguration(): void { $errorMessage .= "- {$item}\n"; } - $settingsHint = 'in the SoftwareCatalog settings before importing.'; + $settingsHint = 'in the Stackiq settings before importing.'; $errorMessage .= "\nPlease configure the AMEF register and all required schema IDs $settingsHint"; $manualHint = 'or set them manually via the admin interface.'; $errorMessage .= "\nYou can use the auto-configuration feature $manualHint"; @@ -1615,7 +1615,7 @@ private function createTempFile(string $content): string { * @spec openspec/specs/archimate-import/spec.md */ private function resolveConfiguredId(string $key): ?string { - $value = $this->config->getValueString('softwarecatalog', $key, ''); + $value = $this->config->getValueString('stackiq', $key, ''); if (trim($value) === '') { $this->logger->warning( 'ArchiMate configuration is incomplete — this id is not configured, so it is omitted rather than passed on as an empty string', @@ -1639,7 +1639,7 @@ public function getAmefConfig(): array { try { // Get configuration from app config using the correct method. - $config = $this->config->getValueString('softwarecatalog', 'amef_config', '{}'); + $config = $this->config->getValueString('stackiq', 'amef_config', '{}'); $decoded = json_decode($config, true); if (is_array($decoded) === false) { @@ -1757,10 +1757,10 @@ private function getAmefRegisterId(): ?int { // Fallback to legacy individual app config keys if not present in JSON. if ($rawRegisterId === null || $rawRegisterId === '') { - $rawRegisterId = $this->config->getValueString('softwarecatalog', 'amef_register_id', ''); - if ($this->config->getValueString('softwarecatalog', 'amef_register', '') !== '') { + $rawRegisterId = $this->config->getValueString('stackiq', 'amef_register_id', ''); + if ($this->config->getValueString('stackiq', 'amef_register', '') !== '') { // If only the plain register key is configured, use it as the ID. - $rawRegisterId = $this->config->getValueString('softwarecatalog', 'amef_register', ''); + $rawRegisterId = $this->config->getValueString('stackiq', 'amef_register', ''); } } diff --git a/lib/Service/Contactpersoon/ContactValidator.php b/lib/Service/Contactpersoon/ContactValidator.php index fe909c68..eb8e7e66 100644 --- a/lib/Service/Contactpersoon/ContactValidator.php +++ b/lib/Service/Contactpersoon/ContactValidator.php @@ -1,17 +1,17 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/method-decomposition/tasks.md#task-7 * @@ -21,7 +21,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\Contactpersoon; +namespace OCA\Stackiq\Service\Contactpersoon; use InvalidArgumentException; diff --git a/lib/Service/ContactpersoonService.php b/lib/Service/ContactpersoonService.php index 44b1f9ba..6df8a9a2 100644 --- a/lib/Service/ContactpersoonService.php +++ b/lib/Service/ContactpersoonService.php @@ -4,26 +4,26 @@ * Contactpersoon Service * * This file contains the service class for handling contact person-specific operations - * in the SoftwareCatalog application. + * in the Stackiq application. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\ContactPersonHandler; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\GroupHandler; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\HierarchyHandler; +use OCA\Stackiq\Service\Stackiq\ContactPersonHandler; +use OCA\Stackiq\Service\Stackiq\GroupHandler; +use OCA\Stackiq\Service\Stackiq\HierarchyHandler; use OCP\App\IAppManager; use OCP\AppFramework\Db\DoesNotExistException; use OCP\IAppConfig; @@ -37,11 +37,11 @@ * user account creation, and group management. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @SuppressWarnings(PHPMD.ExcessiveClassLength) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) @@ -173,7 +173,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat ); try { $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); - $settingsService = $this->container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->container->get('OCA\Stackiq\Service\SettingsService'); $voorzieningenConfig = $settingsService->getVoorzieningenConfig(); $orgObject = $objectService->find( id: $organizationUuid, @@ -186,7 +186,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat $orgData = $orgObject->getObject(); $orgStatus = strtolower(($orgData['status'] ?? '')); if (in_array(needle: $orgStatus, haystack: ['actief', 'active']) === true) { - $syncServiceClass = 'OCA\SoftwareCatalog\Service\OrganizationSyncService'; + $syncServiceClass = 'OCA\Stackiq\Service\OrganizationSyncService'; $organizationSyncService = $this->container->get($syncServiceClass); $backupStats = [ 'entitiesCreated' => 0, diff --git a/lib/Service/ContractApprovalService.php b/lib/Service/ContractApprovalService.php index 231240df..8738993f 100644 --- a/lib/Service/ContractApprovalService.php +++ b/lib/Service/ContractApprovalService.php @@ -8,7 +8,7 @@ * expiring/`Verlopen` contract) to decidesk — the canonical fleet decision * authority (cross-app interface contract #1) — through the in-process * `IEventDispatcher` event contract (`OCA\Decidesk\Event\DecisionRequestedEvent` - * / `DecisionConcludedEvent`). softwarecatalog keeps the contract RECORD locally + * / `DecisionConcludedEvent`). stackiq keeps the contract RECORD locally * and PROJECTS the decidesk outcome onto two catalog-local fields * (`approvalDecisionId`, `approvalState`). * @@ -21,11 +21,11 @@ * never set to `Actief` on local authority. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/contract-decision-delegation/spec.md * @@ -35,7 +35,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCP\EventDispatcher\IEventDispatcher; @@ -65,8 +65,21 @@ class ContractApprovalService { /** * This consumer app id, stamped on the request event as `sourceApp` and * used by the conclusion listener to filter inbound events. + * + * FROZEN at `stackiq` through the app-id rename. This value is not + * a name we own at read time — it is PERSISTED on decidesk's Decision rows + * when the approval is raised, and `DecisionConcludedListener` matches + * inbound conclusions against it. Every decision already open was stamped + * `stackiq`; moving the constant makes the filter miss them, so + * their outcomes are dropped on the floor and the contract never leaves + * `In onderhandeling`. Nothing errors — a filtered-out event looks exactly + * like an event that was never sent. + * + * It can only move in a coordinated change that also rewrites the stored + * `sourceApp` on decidesk's existing rows, or that accepts both spellings + * on the read side first. */ - public const SOURCE_APP = 'softwarecatalog'; + public const SOURCE_APP = 'stackiq'; /** * The decisionType raised for a first activation of an `In onderhandeling` diff --git a/lib/Service/ContractStatusService.php b/lib/Service/ContractStatusService.php index 3e1f67d4..0e511ad7 100644 --- a/lib/Service/ContractStatusService.php +++ b/lib/Service/ContractStatusService.php @@ -10,11 +10,11 @@ * without an end date, or any manually-set status in another direction. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/contract-administration/spec.md * @@ -24,7 +24,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use DateTimeImmutable; use OCA\OpenRegister\Contract\ObjectServiceInterface; diff --git a/lib/Service/EolMatcherService.php b/lib/Service/EolMatcherService.php index c55b78fe..112b4128 100644 --- a/lib/Service/EolMatcherService.php +++ b/lib/Service/EolMatcherService.php @@ -15,11 +15,11 @@ * nulled), plus the two provenance fields. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/eol-feed-integration/spec.md#requirement-version-matching-is-conservative-and-unambiguous-only * @spec openspec/specs/eol-feed-integration/spec.md#requirement-stamping-preserves-every-other-field-and-records-provenance @@ -30,7 +30,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; /** * Conservative version-prefix matcher between `moduleVersie.versie` and diff --git a/lib/Service/EolSyncService.php b/lib/Service/EolSyncService.php index 2d21cb63..ae919b91 100644 --- a/lib/Service/EolSyncService.php +++ b/lib/Service/EolSyncService.php @@ -15,11 +15,11 @@ * "sync now" admin endpoint, so the two trigger paths can never drift. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/eol-feed-integration/spec.md#requirement-eol-sync-runs-on-a-schedule-with-a-manual-trigger * @spec openspec/specs/eol-feed-integration/spec.md#requirement-the-feature-degrades-gracefully-when-the-feed-is-unavailable @@ -31,7 +31,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCP\AppFramework\Utility\ITimeFactory; @@ -352,7 +352,7 @@ private function fetchCycles(ObjectServiceInterface $objectService, array $confi * Fetch the `moduleVersie` rows belonging to one module. * * @param ObjectServiceInterface $objectService The OpenRegister object service. - * @param int $moduleRegisterId The (softwarecatalog) module register id. + * @param int $moduleRegisterId The (stackiq) module register id. * @param int $versionSchemaId The moduleVersie schema id. * @param string $moduleUuid The owning module's uuid. * diff --git a/lib/Service/FacetService.php b/lib/Service/FacetService.php index a3748455..48bb6b1e 100644 --- a/lib/Service/FacetService.php +++ b/lib/Service/FacetService.php @@ -1,7 +1,7 @@ * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * SPDX-FileCopyrightText: 2026 Conduction B.V. * SPDX-License-Identifier: EUPL-1.2 @@ -23,7 +23,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use InvalidArgumentException; use OCA\OpenRegister\Contract\ObjectServiceInterface; @@ -46,7 +46,7 @@ * by its own selection") facet counts over that map. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * * @spec openspec/specs/gemma-faceted-search/spec.md#requirement-facet-aggregation-endpoint-returns-gemma-dimension-counts * @@ -130,7 +130,7 @@ public function __construct( private readonly LoggerInterface $logger, ICacheFactory $cacheFactory, ) { - $this->facetsCache = $cacheFactory->createDistributed(prefix: 'softwarecatalog_facets'); + $this->facetsCache = $cacheFactory->createDistributed(prefix: 'stackiq_facets'); }//end __construct() diff --git a/lib/Service/Federation/FederationConfig.php b/lib/Service/Federation/FederationConfig.php index 6125fbc5..fc31c52d 100644 --- a/lib/Service/Federation/FederationConfig.php +++ b/lib/Service/Federation/FederationConfig.php @@ -3,17 +3,17 @@ /** * Federation configuration value object. * - * Reads the softwarecatalog federation app-config keys via IAppConfig and + * Reads the stackiq federation app-config keys via IAppConfig and * exposes them as a small immutable value object so callers never touch raw * config keys. Defaults match the spec (directory.opencatalogi.nl, federation * disabled, no peers, hourly sync). * * @category Service - * @package OCA\SoftwareCatalog\Service\Federation + * @package OCA\Stackiq\Service\Federation * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/federated-catalog-sync/spec.md * @@ -23,9 +23,9 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\Federation; +namespace OCA\Stackiq\Service\Federation; -use OCA\SoftwareCatalog\AppInfo\Application; +use OCA\Stackiq\AppInfo\Application; use OCP\IAppConfig; /** diff --git a/lib/Service/Federation/FederationMerger.php b/lib/Service/Federation/FederationMerger.php index 8850261d..470fc7b5 100644 --- a/lib/Service/Federation/FederationMerger.php +++ b/lib/Service/Federation/FederationMerger.php @@ -16,11 +16,11 @@ * therefore treated as read-only by every local write path (isPeerSourced()). * * @category Service - * @package OCA\SoftwareCatalog\Service\Federation + * @package OCA\Stackiq\Service\Federation * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/federated-catalog-sync/spec.md * @@ -30,7 +30,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\Federation; +namespace OCA\Stackiq\Service\Federation; /** * Reconciles a peer's published entries with the locally-stored peer mirrors. diff --git a/lib/Service/Federation/FederationService.php b/lib/Service/Federation/FederationService.php index c63acc95..2bd60c10 100644 --- a/lib/Service/Federation/FederationService.php +++ b/lib/Service/Federation/FederationService.php @@ -5,17 +5,17 @@ * * Cross-instance catalog federation by DELEGATING to OpenCatalogi's proven * federation stack (DirectoryService / BroadcastService) — never a bespoke - * wire protocol (design constraint). softwarecatalog contributes only its + * wire protocol (design constraint). stackiq contributes only its * schema mapping, the merge/provenance semantics, the sync schedule, and the * admin controls. When OpenCatalogi is not installed, every entry point * degrades to a clean disabled state with a clear message — it never errors. * * @category Service - * @package OCA\SoftwareCatalog\Service\Federation + * @package OCA\Stackiq\Service\Federation * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/federated-catalog-sync/spec.md * @@ -25,9 +25,9 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\Federation; +namespace OCA\Stackiq\Service\Federation; -use OCA\SoftwareCatalog\Service\SettingsService; +use OCA\Stackiq\Service\SettingsService; use OCP\App\IAppManager; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -384,7 +384,7 @@ public function pullPeer(string $peerUrl): array { /** * Fetch a peer's published catalog entries via OpenCatalogi's DirectoryService. * - * Delegates the wire to OpenCatalogi — softwarecatalog never speaks a bespoke + * Delegates the wire to OpenCatalogi — stackiq never speaks a bespoke * federation protocol. Only published entries are returned (the peer's own * `publicatiedatum<=$now` public RBAC gate governs that surface). * diff --git a/lib/Service/GebruikService.php b/lib/Service/GebruikService.php index 24cb777b..ba7aeb4c 100644 --- a/lib/Service/GebruikService.php +++ b/lib/Service/GebruikService.php @@ -6,15 +6,15 @@ * Service for retrieving and managing Gebruik (usage) objects. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use Exception; use OCA\OpenRegister\Contract\ObjectServiceInterface; diff --git a/lib/Service/GebruikSyncService.php b/lib/Service/GebruikSyncService.php index f581203f..c0931b96 100644 --- a/lib/Service/GebruikSyncService.php +++ b/lib/Service/GebruikSyncService.php @@ -10,7 +10,7 @@ * - Auto-updating status based on date fields * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Ruben van der Linde * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl @@ -22,19 +22,19 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use DateTime; use Exception; +use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCA\OpenRegister\Db\ObjectEntity; use Psr\Log\LoggerInterface; -use OCA\OpenRegister\Contract\ObjectServiceInterface; /** * Service for synchronizing and processing Gebruik (Usage) objects. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Ruben van der Linde * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl * @version GIT: @@ -113,7 +113,7 @@ public function processSpecificGebruik(ObjectEntity $gebruikObject): array { $this->logger->debug( 'Processing gebruik object', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikUuid, 'currentStatus' => $gebruikData['status'] ?? 'Unknown', ] @@ -135,7 +135,7 @@ public function processSpecificGebruik(ObjectEntity $gebruikObject): array { $this->logger->critical( 'GEBRUIK PROCESSING COMPLETED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikUuid, 'stats' => $stats, 'processingTime' => $stats['duration'] . 's', @@ -150,7 +150,7 @@ public function processSpecificGebruik(ObjectEntity $gebruikObject): array { $this->logger->error( 'GEBRUIK PROCESSING ERROR', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikObject->getUuid(), 'exception' => $e->getMessage(), 'file' => $e->getFile(), @@ -199,7 +199,7 @@ private function processAmefElements(ObjectEntity $gebruikObject): array { $this->logger->debug( 'Processing referentiecomponenten', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikUuid, 'referentieComponentenCount' => count($referenceComponents), ] @@ -233,7 +233,7 @@ private function processAmefElements(ObjectEntity $gebruikObject): array { $this->logger->error( 'AMEF configuration missing', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'amefRegister' => $amefRegister, 'elementSchema' => $elementSchema, ] @@ -278,7 +278,7 @@ private function processAmefElements(ObjectEntity $gebruikObject): array { $this->logger->critical( 'AMEF ELEMENTS UPDATED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikUuid, 'amefSlugs' => $amefSlugs, 'amefElementsCount' => count($amefSlugs), @@ -292,7 +292,7 @@ private function processAmefElements(ObjectEntity $gebruikObject): array { $this->logger->error( 'AMEF PROCESSING ERROR', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikObject->getUuid(), 'exception' => $e->getMessage(), ] @@ -337,7 +337,7 @@ private function searchAmefElementsByIds(array $ids, string $register, string $s $this->logger->warning( 'Failed to search for AMEF element', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'id' => $id, 'error' => $e->getMessage(), ] @@ -348,7 +348,7 @@ private function searchAmefElementsByIds(array $ids, string $register, string $s $this->logger->info( 'AMEF elements search completed', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'searchedIds' => $ids, 'foundElementsCount' => count($foundElements), ] @@ -382,7 +382,7 @@ private function updateStatusBasedOnDates(ObjectEntity $gebruikObject): array { $this->logger->info( 'CHECKING STATUS DATES', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikUuid, 'currentStatus' => $currentStatus, 'statusDates' => $statusDates, @@ -402,7 +402,7 @@ private function updateStatusBasedOnDates(ObjectEntity $gebruikObject): array { $this->logger->critical( 'STATUS AUTO-UPDATED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikUuid, 'oldStatus' => $currentStatus, 'newStatus' => $targetStatus, @@ -417,7 +417,7 @@ private function updateStatusBasedOnDates(ObjectEntity $gebruikObject): array { $this->logger->error( 'STATUS UPDATE ERROR', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikObject->getUuid(), 'exception' => $e->getMessage(), ] @@ -471,7 +471,7 @@ private function resolveLatestEligibleStatus(array $statusDates, string $gebruik $this->logger->warning( 'Invalid date format', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikUuid, 'status' => $status, 'dateString' => $dateString, @@ -526,7 +526,7 @@ private function updateGebruikObject(ObjectEntity $gebruikObject, array $updated $this->logger->info( 'Gebruik object updated successfully', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikObject->getUuid(), ] ); @@ -534,7 +534,7 @@ private function updateGebruikObject(ObjectEntity $gebruikObject, array $updated $this->logger->error( 'Failed to update gebruik object', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'gebruikId' => $gebruikObject->getUuid(), 'error' => $e->getMessage(), ] diff --git a/lib/Service/IntakeService.php b/lib/Service/IntakeService.php index b0792ee8..83adf120 100644 --- a/lib/Service/IntakeService.php +++ b/lib/Service/IntakeService.php @@ -17,11 +17,11 @@ * admin-gated step (ModerationService). * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/open-data-publishing/spec.md * @@ -31,7 +31,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -270,7 +270,7 @@ private function resolveTarget(): ?array { * FALSE, and because an object is not an array the array arm below cannot * rescue it — so this method used to return `null` for EVERY real save, * putting `uuid: null` in the submit response and the audit log - * (softwarecatalog#490). `property_exists()` is the instrument + * (stackiq#490). `property_exists()` is the instrument * `Entity::getter()` itself decides on; `method_exists()` is kept as the * second arm for genuinely concrete accessors, and the call is wrapped * because neither probe guarantees the other object's shape. diff --git a/lib/Service/MergeOrganisatieService.php b/lib/Service/MergeOrganisatieService.php index b9200008..9bf9ad06 100644 --- a/lib/Service/MergeOrganisatieService.php +++ b/lib/Service/MergeOrganisatieService.php @@ -46,11 +46,11 @@ * - compliancy: `@self.organisation` (system-level owning organisation). * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/organisation-merge/spec.md * @@ -60,10 +60,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\OrganizationHandler; +use OCA\Stackiq\Service\Stackiq\OrganizationHandler; use OCP\App\IAppManager; use OCP\EventDispatcher\IEventDispatcher; use OCP\IGroupManager; @@ -75,10 +75,10 @@ * Service orchestrating organisation-merge dry-run and execute. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/organisation-merge/spec.md * @@ -472,7 +472,7 @@ private function repointBySelfOrganisation(string $objectType, string $source, s * wrong here, and both fail silently: * * - `method_exists()` is **false** for every such accessor. That was - * softwarecatalog#490: the caller's re-point branch never ran, so a merge + * stackiq#490: the caller's re-point branch never ran, so a merge * re-pointed nothing for `contract`/`compliancy` while still tombstoning * the source organisation. * - `is_callable()` is **true** for ANY name on a class with `__call()`, so diff --git a/lib/Service/ModerationService.php b/lib/Service/ModerationService.php index 48565f88..62dfac8a 100644 --- a/lib/Service/ModerationService.php +++ b/lib/Service/ModerationService.php @@ -5,7 +5,7 @@ * * The admin-only counterpart to IntakeService (organisatie) and * ReviewService (beoordeeling) — a single generalised mechanism, not two - * parallel ones (catalog-ratings, softwarecatalog#375: "reuse the + * parallel ones (catalog-ratings, stackiq#375: "reuse the * ModerationQueue.vue pattern... do not invent a second moderation * mechanism"). Every method takes an explicit `$type` selecting which * moderated type/field/values to operate on; it defaults to the original @@ -28,11 +28,11 @@ * ModerationController. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/open-data-publishing/spec.md * @spec openspec/specs/catalog-ratings/spec.md#requirement-review-moderation-must-reuse-the-existing-moderation-queue-mechanism-not-a-second-one @@ -43,7 +43,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; diff --git a/lib/Service/ModuleComplianceService.php b/lib/Service/ModuleComplianceService.php index dfb181c8..5b18c436 100644 --- a/lib/Service/ModuleComplianceService.php +++ b/lib/Service/ModuleComplianceService.php @@ -4,22 +4,22 @@ * Module Compliance Service * * This file contains the service class for handling module compliance logic - * in the SoftwareCatalog application. + * in the Stackiq application. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Container\ContainerInterface; @@ -32,11 +32,11 @@ * property based on linked compliance objects and their standaardversie references. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity) diff --git a/lib/Service/ModuleEventProcessor.php b/lib/Service/ModuleEventProcessor.php index dc943e4d..e90af878 100644 --- a/lib/Service/ModuleEventProcessor.php +++ b/lib/Service/ModuleEventProcessor.php @@ -1,17 +1,17 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/method-decomposition/tasks.md#task-6 * @@ -21,13 +21,13 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; /** - * Handles shared module-event processing logic extracted from SoftwareCatalogEventListener. + * Handles shared module-event processing logic extracted from StackiqEventListener. * * This processor centralises the schema-ID lookup, early-guard, and delegation * steps that were duplicated across handleObjectCreated / handleObjectUpdated / @@ -93,18 +93,18 @@ public function processOrganisatieCreated(object $object, array $schemaIds): voi if (in_array(needle: $status, haystack: ['actief', 'active']) !== true) { $this->logger->debug( - 'SoftwareCatalog: Skipping non-active organization creation', + 'Stackiq: Skipping non-active organization creation', ['objectId' => $object->getUuid(), 'status' => $status] ); return; } try { - $orgSyncService = $this->container->get('OCA\SoftwareCatalog\Service\OrganizationSyncService'); + $orgSyncService = $this->container->get('OCA\Stackiq\Service\OrganizationSyncService'); $orgSyncService->processSpecificOrganization($object); } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog: Failed to process organization creation', + 'Stackiq: Failed to process organization creation', ['objectId' => $object->getUuid(), 'exception' => $e->getMessage()] ); } @@ -164,16 +164,16 @@ public function processOrganisatieDeleted(object $object, array $schemaIds): boo } $this->logger->info( - 'SoftwareCatalog: Processing organization deletion', + 'Stackiq: Processing organization deletion', ['objectId' => $object->getUuid()] ); try { - $orgSyncService = $this->container->get('OCA\SoftwareCatalog\Service\OrganizationSyncService'); + $orgSyncService = $this->container->get('OCA\Stackiq\Service\OrganizationSyncService'); $orgSyncService->processSpecificOrganization($object); } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog: Failed to process organization deletion', + 'Stackiq: Failed to process organization deletion', ['objectId' => $object->getUuid(), 'exception' => $e->getMessage()] ); } @@ -193,7 +193,7 @@ private function processActiveOrganisationUpdate(object $object, string $status) $objectId = $object->getUuid(); $this->logger->info( - 'SoftwareCatalog: Processing active organization update', + 'Stackiq: Processing active organization update', ['objectId' => $objectId, 'status' => $status] ); @@ -212,11 +212,11 @@ private function processActiveOrganisationUpdate(object $object, string $status) _multitenancy: false ); - $orgSyncService = $this->container->get('OCA\SoftwareCatalog\Service\OrganizationSyncService'); + $orgSyncService = $this->container->get('OCA\Stackiq\Service\OrganizationSyncService'); $orgSyncService->processSpecificOrganization($orgWithContacts); } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog: Failed to process organization update', + 'Stackiq: Failed to process organization update', ['objectId' => $objectId, 'exception' => $e->getMessage()] ); }//end try diff --git a/lib/Service/ModuleRegistrationService.php b/lib/Service/ModuleRegistrationService.php index 43606e83..5fede71c 100644 --- a/lib/Service/ModuleRegistrationService.php +++ b/lib/Service/ModuleRegistrationService.php @@ -7,19 +7,19 @@ * based on the owning organisation's type. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Container\ContainerInterface; @@ -30,7 +30,7 @@ * based on the owning organisation's type. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service */ class ModuleRegistrationService { /** diff --git a/lib/Service/ModuleVersionService.php b/lib/Service/ModuleVersionService.php index 4efb3d02..d00ed17c 100644 --- a/lib/Service/ModuleVersionService.php +++ b/lib/Service/ModuleVersionService.php @@ -8,19 +8,19 @@ * the module's name and description. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: 1.0.0 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Container\ContainerInterface; @@ -35,7 +35,7 @@ * (`fetchVersionData()`, `compareVersions()`, `updateVersionRecord()`). * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * * @spec openspec/changes/method-decomposition/tasks.md#task-9-5 */ diff --git a/lib/Service/OrganisatieService.php b/lib/Service/OrganisatieService.php index 9a1029ac..7c77a9a2 100644 --- a/lib/Service/OrganisatieService.php +++ b/lib/Service/OrganisatieService.php @@ -4,22 +4,22 @@ * Organisatie Service. * * This file contains the service class for handling organization-specific operations - * in the SoftwareCatalog application. + * in the Stackiq application. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\OrganizationHandler; +use OCA\Stackiq\Service\Stackiq\OrganizationHandler; use OCP\App\IAppManager; use OCP\IAppConfig; use OCP\IUserManager; @@ -33,11 +33,11 @@ * status management, and integration with OpenRegister. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ @@ -153,7 +153,7 @@ public function updateOrganizationStatus(string $organizationUuid, array $object $organisationMapper = $this->container->get('OCA\OpenRegister\Db\OrganisationMapper'); $organisationEntity = $organisationMapper->findByUuid($organizationUuid); - // Map status from SoftwareCatalog to OpenRegister. + // Map status from Stackiq to OpenRegister. $active = $this->mapStatus(status: $objectData['beoordeling'] ?? 'actief'); // Update the entity. @@ -200,7 +200,7 @@ private function getOrganisationService(): ?\OCA\OpenRegister\Service\Organisati }//end getOrganisationService() /** - * Maps organization data from Software Catalog object to OpenRegister format. + * Maps organization data from Stackiq object to OpenRegister format. * * @param array $objectData The organization object data. * @@ -229,9 +229,9 @@ private function mapOrganizationDataForOpenRegister(array $objectData): array { }//end mapOrganizationDataForOpenRegister() /** - * Maps status from Software Catalog to OpenRegister format. + * Maps status from Stackiq to OpenRegister format. * - * @param string $status The status from Software Catalog + * @param string $status The status from Stackiq * * @return bool The mapped active status for OpenRegister * diff --git a/lib/Service/OrganizationSyncService.php b/lib/Service/OrganizationSyncService.php index d598cf2b..8ae3062e 100644 --- a/lib/Service/OrganizationSyncService.php +++ b/lib/Service/OrganizationSyncService.php @@ -4,41 +4,41 @@ * Organization Synchronization Service * * This file contains the service class for synchronizing organizations and contact persons - * between SoftwareCatalog objects and OpenRegister entities. + * between Stackiq objects and OpenRegister entities. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\ContactPersonHandler; +use OCA\OpenRegister\Db\OrganisationMapper; +use OCA\Stackiq\Service\Stackiq\ContactPersonHandler; use OCP\IAppConfig; use OCP\IDBConnection; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; -use OCA\OpenRegister\Db\OrganisationMapper; /** * Service for synchronizing organizations and contact persons. * - * This service provides comprehensive synchronization between SoftwareCatalog objects + * This service provides comprehensive synchronization between Stackiq objects * and OpenRegister entities, ensuring data consistency and proper user management. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @SuppressWarnings(PHPMD.ExcessiveClassLength) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) @@ -995,7 +995,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $this->logger->debug( 'Ensuring organisation entity', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organisatieId' => $organisationId, 'name' => ($objectData['name'] ?? 'Unknown'), 'status' => ($objectData['status'] ?? 'Unknown'), @@ -1019,7 +1019,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $this->logger->debug( 'Existing entity found', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organisatieId' => $organisationId, 'entityId' => $organisationEntity->getId(), 'shouldBeActive' => $shouldBeActive, @@ -1031,7 +1031,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $this->logger->debug( 'Updating entity status', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organisatieId' => $organisationId, 'oldActive' => $organisationEntity->getActive(), 'newActive' => $shouldBeActive, @@ -1087,7 +1087,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $this->logger->info( 'OrganizationSyncService: Found existing entity by slug, updating UUID to match object', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organisatieId' => $organisationId, 'oldEntityUuid' => $organisationEntity->getUuid(), 'slug' => $slug, @@ -1116,7 +1116,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $this->logger->debug( 'Creating new organisation entity', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organisatieId' => $organisationId, 'name' => ($objectData['name'] ?? 'Unknown'), ] @@ -1128,7 +1128,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $this->logger->debug( 'New organisation entity created', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organisatieId' => $organisationId, 'entityId' => $organisationEntity->getId(), 'active' => $organisationEntity->getActive(), @@ -1171,7 +1171,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $this->logger->error( '❌ ORGANISATION ENTITY CREATION FAILED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organisatieId' => $organisationId, ] ); @@ -1183,7 +1183,7 @@ private function ensureOrganisationEntity(object $organisationObject, array &$st $this->logger->error( '💥 ENSURE ORGANISATION ENTITY EXCEPTION', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organisatieId' => $organisationObject->getId(), 'exception' => $e->getMessage(), 'file' => $e->getFile(), @@ -1606,7 +1606,7 @@ public function getSyncStatus(int $minutesBack = 10): array { // Configuration. 'contactSchemaConfigured' => empty($contactSchema) === false, - 'lastSyncTime' => $this->config->getValueString('softwarecatalog', 'last_sync_time', 'Never'), + 'lastSyncTime' => $this->config->getValueString('stackiq', 'last_sync_time', 'Never'), // Email configuration status. 'emailStatus' => $this->getEmailConfigurationStatus(), @@ -1671,7 +1671,7 @@ private function formatNumber(int $number): string { * @spec openspec/specs/organization-sync/spec.md */ public function recordSyncTime(): void { - $this->config->setValueString('softwarecatalog', 'last_sync_time', date('Y-m-d H:i:s')); + $this->config->setValueString('stackiq', 'last_sync_time', date('Y-m-d H:i:s')); }//end recordSyncTime() @@ -1705,7 +1705,7 @@ public function processSpecificOrganization($organizationObject): array { $this->logger->info( '🏢 ORGANIZATION PROCESSING STARTED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'trigger' => 'ObjectCreatedEvent', 'organizationId' => $organizationUuid, 'organizationName' => ($objectData['name'] ?? 'Unknown'), @@ -1732,7 +1732,7 @@ public function processSpecificOrganization($organizationObject): array { $this->logger->info( '✅ ORGANISATION ENTITY CREATED/UPDATED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationUuid' => $organizationUuid, 'entityId' => $organisationEntity->getId(), 'entityActive' => $organisationEntity->getActive(), @@ -1772,7 +1772,7 @@ public function processSpecificOrganization($organizationObject): array { $this->logger->error( '❌ ORGANISATION ENTITY FAILED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationUuid' => $organizationUuid, 'error' => 'Failed to create/update organisation entity', ] @@ -1786,7 +1786,7 @@ public function processSpecificOrganization($organizationObject): array { $this->logger->info( '🏁 ORGANIZATION PROCESSING COMPLETED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationId' => $organizationUuid, 'stats' => $stats, 'processingTime' => $stats['duration'] . 's', @@ -1799,7 +1799,7 @@ public function processSpecificOrganization($organizationObject): array { $this->logger->error( '💥 ORGANIZATION PROCESSING EXCEPTION', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationId' => $organizationObject->getUuid(), 'exception' => $e->getMessage(), 'file' => $e->getFile(), @@ -1840,7 +1840,7 @@ private function processNestedContactPersons($organizationObject, array &$stats) $this->logger->info( '👥 PROCESSING NESTED CONTACT PERSONS', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationId' => $organizationUuid, 'contactCount' => count($contactPersons), ] @@ -1968,7 +1968,7 @@ private function processRelatedContactPersons(string $organizationUuid, $organiz $this->logger->debug( 'Finding related contact persons', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationId' => $organizationUuid, ] ); @@ -2121,7 +2121,7 @@ private function processRelatedContactPersons(string $organizationUuid, $organiz $this->logger->info( '👥 PROCESSING RELATED CONTACT PERSONS', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationId' => $organizationUuid, 'contactCount' => count($relatedContacts), ] @@ -2284,7 +2284,7 @@ private function createOrUpdateContactPersonObject( $this->logger->info( '📧 FETCHING EXISTING CONTACT PERSON', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationId' => $organizationUuid, 'contactId' => $existingContactId, 'email' => $email, @@ -2316,7 +2316,7 @@ private function createOrUpdateContactPersonObject( $this->logger->info( '📧 CREATING NEW CONTACT PERSON OBJECT', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationId' => $organizationUuid, 'email' => $email, 'name' => ($contactData['voornaam'] ?? '') . ' ' . ($contactData['achternaam'] ?? ''), @@ -2398,7 +2398,7 @@ private function createOrUpdateContactPersonObject( $this->logger->info( '✅ CONTACT PERSON OBJECT READY', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationId' => $organizationUuid, 'contactId' => $contactObject->getUuid(), 'email' => $email, @@ -2417,7 +2417,7 @@ private function createOrUpdateContactPersonObject( $this->logger->info( 'Organisation entity missing for ' . $organizationUuid . ', creating backup entity', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactObject->getUuid(), ] ); @@ -2442,7 +2442,7 @@ private function createOrUpdateContactPersonObject( $this->logger->error( 'Backup org entity creation failed', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationId' => $organizationUuid, 'error' => $backupEx->getMessage(), ] @@ -2461,7 +2461,7 @@ private function createOrUpdateContactPersonObject( $this->logger->info( 'Creating user account for contact person (org is active)', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactObject->getUuid(), 'organizationId' => $organizationUuid, 'email' => $email, @@ -2496,7 +2496,7 @@ private function createOrUpdateContactPersonObject( $this->logger->debug( 'Saving contact with username via direct mapper update', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactObject->getUuid(), 'username' => $user->getUID(), 'hasOrganisatie' => isset($contactObjectData['organization']) === true, @@ -2519,7 +2519,7 @@ private function createOrUpdateContactPersonObject( $this->logger->info( 'Contact saved with username', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactObject->getUuid(), 'username' => $user->getUID(), ] @@ -2528,7 +2528,7 @@ private function createOrUpdateContactPersonObject( $this->logger->warning( 'Failed to save username to contact object (user was created)', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactObject->getUuid(), 'username' => $user->getUID(), 'error' => $saveEx->getMessage(), @@ -2555,7 +2555,7 @@ private function createOrUpdateContactPersonObject( $this->logger->info( 'User account created', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactObject->getUuid(), 'username' => $user->getUID(), ] @@ -2566,7 +2566,7 @@ private function createOrUpdateContactPersonObject( $this->logger->error( 'User account creation failed', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactObject->getUuid(), 'email' => $email, ] @@ -2684,7 +2684,7 @@ public function processSpecificContactPerson($contactObject): array { $this->logger->info( '[EVENT] Organisation entity missing for ' . $organizationUuid . ', creating backup entity', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactObject->getUuid(), ] ); @@ -2709,7 +2709,7 @@ public function processSpecificContactPerson($contactObject): array { $this->logger->error( 'Backup org entity creation failed', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'organizationId' => $organizationUuid, 'error' => $backupEx->getMessage(), ] @@ -2798,7 +2798,7 @@ public function processSpecificContactPerson($contactObject): array { $this->logger->debug( '[EVENT] Skipping contact - user account creation failed (likely no email)', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactObject->getUuid(), ] ); diff --git a/lib/Service/PortfolioReportDerivation.php b/lib/Service/PortfolioReportDerivation.php index 00e7c1a5..324079fe 100644 --- a/lib/Service/PortfolioReportDerivation.php +++ b/lib/Service/PortfolioReportDerivation.php @@ -13,11 +13,11 @@ * (design.md Decision 3). * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/portfolio-rationalization-time/specs/portfolio-rationalization-time/spec.md * @@ -27,7 +27,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use DateTimeImmutable; diff --git a/lib/Service/PortfolioReportService.php b/lib/Service/PortfolioReportService.php index 2972a813..21612b3a 100644 --- a/lib/Service/PortfolioReportService.php +++ b/lib/Service/PortfolioReportService.php @@ -16,7 +16,7 @@ * {@see PortfolioReportDerivation}. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -30,12 +30,12 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use DateTimeImmutable; use Exception; use OCA\OpenRegister\Contract\ObjectServiceInterface; -use OCA\SoftwareCatalog\AppInfo\Application; +use OCA\Stackiq\AppInfo\Application; use OCP\App\IAppManager; use OCP\IAppConfig; use Psr\Container\ContainerInterface; diff --git a/lib/Service/ProfileFieldMapper.php b/lib/Service/ProfileFieldMapper.php index 3e106f07..26928b40 100644 --- a/lib/Service/ProfileFieldMapper.php +++ b/lib/Service/ProfileFieldMapper.php @@ -1,17 +1,17 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/method-decomposition/tasks.md#task-8 * @@ -21,10 +21,10 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; /** - * Maps Nextcloud user profile field keys to SoftwareCatalog contactpersoon field names. + * Maps Nextcloud user profile field keys to Stackiq contactpersoon field names. * * Used by UserProfileUpdatedEventListener to delegate field-name resolution * without bloating the event-handler method. diff --git a/lib/Service/ProgressTracker.php b/lib/Service/ProgressTracker.php index 066546d2..3e90f642 100644 --- a/lib/Service/ProgressTracker.php +++ b/lib/Service/ProgressTracker.php @@ -7,17 +7,17 @@ * Supports real-time streaming via Server-Sent Events. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: 1.0.0 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCP\ISession; use Psr\Log\LoggerInterface; @@ -26,12 +26,12 @@ * Service for tracking and reporting progress of long-running operations * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: 1.0.0 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ class ProgressTracker { /** diff --git a/lib/Service/PublicationService.php b/lib/Service/PublicationService.php index 73829b55..046a1384 100644 --- a/lib/Service/PublicationService.php +++ b/lib/Service/PublicationService.php @@ -18,11 +18,11 @@ * (public + federation) read surface. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/open-data-publishing/spec.md * @@ -32,7 +32,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Container\ContainerInterface; diff --git a/lib/Service/ReviewAggregateService.php b/lib/Service/ReviewAggregateService.php index 60ec30de..8e13a1d7 100644 --- a/lib/Service/ReviewAggregateService.php +++ b/lib/Service/ReviewAggregateService.php @@ -2,7 +2,7 @@ /** * Public approved-only review aggregate/read path (catalog-ratings, - * softwarecatalog#375) — split out of ReviewService (which owns the + * stackiq#375) — split out of ReviewService (which owns the * authenticated write path) to keep each class under the * ExcessiveClassComplexity budget. * @@ -15,11 +15,11 @@ * matching — computing it here is fully unit-testable regardless of that. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/catalog-ratings/spec.md#requirement-module-and-dienst-detail-pages-must-display-an-aggregate-rating-computed-only-from-approved-reviews * @@ -29,7 +29,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; diff --git a/lib/Service/ReviewService.php b/lib/Service/ReviewService.php index d3183d46..3bc2e1c8 100644 --- a/lib/Service/ReviewService.php +++ b/lib/Service/ReviewService.php @@ -5,7 +5,7 @@ * ReviewAggregateService for the approved-only read/aggregate path; split * to keep each class under the ExcessiveClassComplexity budget). * - * The write path for the `catalog-ratings` feature (softwarecatalog#375). + * The write path for the `catalog-ratings` feature (stackiq#375). * Unlike `IntakeService` (anonymous organisation registration), a review * submission REQUIRES an authenticated Nextcloud session — anonymous public * review submission is explicitly out of scope. The author identity is never @@ -17,11 +17,11 @@ * organisatie moderation pattern) may change that. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/catalog-ratings/spec.md * @@ -31,7 +31,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCP\IUser; use OCP\IUserSession; @@ -359,7 +359,7 @@ private function resolveTarget(): ?array { * FALSE, and because an object is not an array the array arm below cannot * rescue it — so this method used to return `null` for EVERY real save, * putting `uuid: null` in the submit response and the audit log - * (softwarecatalog#490). `property_exists()` is the instrument + * (stackiq#490). `property_exists()` is the instrument * `Entity::getter()` itself decides on; `method_exists()` is kept as the * second arm for genuinely concrete accessors, and the call is wrapped * because neither probe guarantees the other object's shape. diff --git a/lib/Service/SbomImportService.php b/lib/Service/SbomImportService.php index 727f75be..3cdbbfe7 100644 --- a/lib/Service/SbomImportService.php +++ b/lib/Service/SbomImportService.php @@ -22,11 +22,11 @@ * set rather than a mixed old/new set; re-running the import starts clean. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/sbom-import/spec.md#requirement-re-import-replaces-the-previous-component-set-and-is-soft-delete-aware * @@ -36,7 +36,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use DateTime; use OCA\OpenRegister\Contract\ObjectServiceInterface; @@ -101,9 +101,9 @@ public function __construct( * * @return array Import result summary. * - * @throws \OCA\SoftwareCatalog\Exception\UnsupportedSbomFormatException When the - * document's format/version is not supported. - * No component is written in that case. + * @throws \OCA\Stackiq\Exception\UnsupportedSbomFormatException When the + * document's format/version is not supported. + * No component is written in that case. * @throws RuntimeException When the target `moduleVersie` cannot be * resolved, or required configuration is missing. * @@ -215,8 +215,8 @@ public function importForModuleVersie( * * @return array{components: array>, vulnerabilities: array} * - * @throws \OCA\SoftwareCatalog\Exception\UnsupportedSbomFormatException When - * the document's format/version is not supported. + * @throws \OCA\Stackiq\Exception\UnsupportedSbomFormatException When + * the document's format/version is not supported. * * @spec openspec/specs/sbom-import/spec.md#requirement-cyclonedx-sbom-files-are-parsed-into-a-normalized-component-list */ diff --git a/lib/Service/SbomParserService.php b/lib/Service/SbomParserService.php index 5b39319a..6dc19b69 100644 --- a/lib/Service/SbomParserService.php +++ b/lib/Service/SbomParserService.php @@ -20,11 +20,11 @@ * "Alternative considered"). * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/sbom-import/spec.md#requirement-cyclonedx-sbom-files-are-parsed-into-a-normalized-component-list * @@ -34,9 +34,9 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; -use OCA\SoftwareCatalog\Exception\UnsupportedSbomFormatException; +use OCA\Stackiq\Exception\UnsupportedSbomFormatException; /** * Pure CycloneDX 1.5/1.6 (+ optional SPDX 2.x) SBOM parser. diff --git a/lib/Service/Settings/ModuleSettingsHandler.php b/lib/Service/Settings/ModuleSettingsHandler.php index 336bd31a..cb6323ab 100644 --- a/lib/Service/Settings/ModuleSettingsHandler.php +++ b/lib/Service/Settings/ModuleSettingsHandler.php @@ -1,17 +1,17 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/method-decomposition/tasks.md#task-1 * @@ -21,7 +21,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\Settings; +namespace OCA\Stackiq\Service\Settings; use InvalidArgumentException; use OCP\IAppConfig; @@ -42,7 +42,7 @@ class ModuleSettingsHandler { * * @var string */ - private const APP_NAME = 'softwarecatalog'; + private const APP_NAME = 'stackiq'; /** * Constructor. diff --git a/lib/Service/Settings/OrganizationSettingsHandler.php b/lib/Service/Settings/OrganizationSettingsHandler.php index b36a0603..90520263 100644 --- a/lib/Service/Settings/OrganizationSettingsHandler.php +++ b/lib/Service/Settings/OrganizationSettingsHandler.php @@ -1,17 +1,17 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/method-decomposition/tasks.md#task-1 * @@ -21,7 +21,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\Settings; +namespace OCA\Stackiq\Service\Settings; use InvalidArgumentException; use OCP\IAppConfig; @@ -42,7 +42,7 @@ class OrganizationSettingsHandler { * * @var string */ - private const APP_NAME = 'softwarecatalog'; + private const APP_NAME = 'stackiq'; /** * Constructor. diff --git a/lib/Service/Settings/SyncSettingsHandler.php b/lib/Service/Settings/SyncSettingsHandler.php index 05943dc8..53c806ef 100644 --- a/lib/Service/Settings/SyncSettingsHandler.php +++ b/lib/Service/Settings/SyncSettingsHandler.php @@ -1,13 +1,13 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -21,7 +21,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\Settings; +namespace OCA\Stackiq\Service\Settings; use InvalidArgumentException; use OCP\IAppConfig; @@ -42,7 +42,7 @@ class SyncSettingsHandler { * * @var string */ - private const APP_NAME = 'softwarecatalog'; + private const APP_NAME = 'stackiq'; /** * Constructor. diff --git a/lib/Service/SettingsService.php b/lib/Service/SettingsService.php index d354a501..a3ea1b0e 100644 --- a/lib/Service/SettingsService.php +++ b/lib/Service/SettingsService.php @@ -1,10 +1,10 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -16,7 +16,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCP\App\IAppManager; use OCP\IAppConfig; @@ -31,13 +31,13 @@ use Symfony\Component\Mime\Email; /** - * Service for handling settings-related operations in the SoftwareCatalog. + * Service for handling settings-related operations in the Stackiq. * * Provides functionality for retrieving, saving, and loading settings, * as well as managing configuration for different object types. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -152,7 +152,7 @@ public function __construct( private readonly IGroupManager $groupManager, private readonly IL10N $l10n, ) { - $this->appName = 'softwarecatalog'; + $this->appName = 'stackiq'; }//end __construct() /** @@ -1449,7 +1449,7 @@ public function initialize(?string $minOpenRegisterVersion = self::MIN_OPENREGIS $this->logger->info('SettingsService: Loading settings from file'); $loadResult = $this->loadSettings(); $results['settingsLoaded'] = true; - $results['configurationImported'] = empty($loadResult['softwarecatalog_imported']) === false; + $results['configurationImported'] = empty($loadResult['stackiq_imported']) === false; $this->logger->info( 'SettingsService: Settings loaded successfully', [ @@ -1623,7 +1623,7 @@ public function loadSettings(bool $force = false): array { } }//end if - $results['softwarecatalog'] = $softwareCatalogSettings; + $results['stackiq'] = $softwareCatalogSettings; // Import via configuration service if available with version checking. try { @@ -1647,7 +1647,7 @@ public function loadSettings(bool $force = false): array { fragmentSig: $fragmentSig ); - $appId = \OCA\SoftwareCatalog\AppInfo\Application::APP_ID; + $appId = \OCA\Stackiq\AppInfo\Application::APP_ID; // Force-when-stale workaround (register-import-reliability, // https://github.com/ConductionNL/openregister/issues/2075): @@ -1724,7 +1724,7 @@ public function loadSettings(bool $force = false): array { ] ); - $results['softwarecatalog_imported'] = true; + $results['stackiq_imported'] = true; $results['import_result'] = $importResult; // Post-import verification (register-import-reliability): a version-gate @@ -1739,15 +1739,15 @@ public function loadSettings(bool $force = false): array { $results['registerVerification'] = $verification; $this->persistRegisterVerificationStatus(verification: $verification); } catch (\Exception $e) { - $results['softwarecatalog_import_error'] = $e->getMessage(); + $results['stackiq_import_error'] = $e->getMessage(); $this->logger->error( - 'Failed to import softwarecatalog settings: ' . $e->getMessage(), + 'Failed to import stackiq settings: ' . $e->getMessage(), [ 'exception' => $e, 'trace' => $e->getTraceAsString(), 'force_flag' => $force, 'effective_force' => $effectiveForce, - 'app_id' => \OCA\SoftwareCatalog\AppInfo\Application::APP_ID, + 'app_id' => \OCA\Stackiq\AppInfo\Application::APP_ID, ] ); @@ -2477,7 +2477,7 @@ public function redactEmailSecrets(array $settings): array { * @spec openspec/specs/settings-service/spec.md */ public function getEmailSettings(): array { - $this->logger->debug('SoftwareCatalog: Loading email settings from configuration'); + $this->logger->debug('Stackiq: Loading email settings from configuration'); $app = $this->appName; $settings = [ @@ -2620,7 +2620,7 @@ public function getEmailSettings(): array { ]; $this->logger->info( - 'SoftwareCatalog: Email settings loaded from configuration', + 'Stackiq: Email settings loaded from configuration', [ 'enabled' => $settings['enabled'], 'transport_type' => $settings['transportType'], @@ -2951,7 +2951,7 @@ public function getDebugInfo(): array { public function sendTestEmail(string $email, array $emailSettings = []): array { // Validate email address first (business logic moved from controller). if (empty($email) === true) { - $this->logger->warning('SoftwareCatalog: Test email request missing email address'); + $this->logger->warning('Stackiq: Test email request missing email address'); return [ 'success' => false, 'message' => 'Email address is required', @@ -2959,7 +2959,7 @@ public function sendTestEmail(string $email, array $emailSettings = []): array { } $this->logger->info( - 'SoftwareCatalog: Starting sendTestEmail process', + 'Stackiq: Starting sendTestEmail process', [ 'recipient' => $email, 'has_email_settings' => empty($emailSettings) === false, @@ -2969,19 +2969,19 @@ public function sendTestEmail(string $email, array $emailSettings = []): array { try { // Ensure vendor autoloader is loaded. include_once __DIR__ . '/../../vendor/autoload.php'; - $this->logger->debug('SoftwareCatalog: Vendor autoloader loaded'); + $this->logger->debug('Stackiq: Vendor autoloader loaded'); // Use provided settings or fall back to stored settings. if (empty($emailSettings) === true) { $emailSettings = $this->getEmailSettings(); - $this->logger->info('SoftwareCatalog: Loaded email settings from storage'); + $this->logger->info('Stackiq: Loaded email settings from storage'); } else { - $this->logger->info('SoftwareCatalog: Using provided email settings'); + $this->logger->info('Stackiq: Using provided email settings'); } // Log the email configuration (without sensitive data). $this->logger->info( - 'SoftwareCatalog: Email configuration', + 'Stackiq: Email configuration', [ 'enabled' => $emailSettings['enabled'] ?? false, 'transport_type' => $emailSettings['transportType'] ?? 'unknown', @@ -2994,7 +2994,7 @@ public function sendTestEmail(string $email, array $emailSettings = []): array { // Check if email is enabled. if (($emailSettings['enabled'] ?? false) === false) { - $this->logger->warning('SoftwareCatalog: Email notifications are disabled'); + $this->logger->warning('Stackiq: Email notifications are disabled'); return [ 'success' => false, 'message' => 'Email notifications are disabled', @@ -3004,7 +3004,7 @@ public function sendTestEmail(string $email, array $emailSettings = []): array { // Use test receiver override if configured. $recipient = $emailSettings['testReceiverOverride'] ?? $email; $this->logger->info( - 'SoftwareCatalog: Final recipient determined', + 'Stackiq: Final recipient determined', [ 'original_recipient' => $email, 'final_recipient' => $recipient, @@ -3013,12 +3013,12 @@ public function sendTestEmail(string $email, array $emailSettings = []): array { ); // Create transport based on configuration. - $this->logger->info('SoftwareCatalog: Creating email transport'); + $this->logger->info('Stackiq: Creating email transport'); $transport = $this->createEmailTransport(emailSettings: $emailSettings); - $this->logger->info('SoftwareCatalog: Email transport created successfully'); + $this->logger->info('Stackiq: Email transport created successfully'); $mailer = new Mailer($transport); - $this->logger->info('SoftwareCatalog: Mailer instance created'); + $this->logger->info('Stackiq: Mailer instance created'); // Create test email. $senderEmail = $emailSettings['senderEmail'] ?? 'noreply@softwarecatalogus.nl'; @@ -3026,7 +3026,7 @@ public function sendTestEmail(string $email, array $emailSettings = []): array { $transportType = $emailSettings['transportType'] ?? 'smtp'; $this->logger->info( - 'SoftwareCatalog: Creating email message', + 'Stackiq: Creating email message', [ 'sender_email' => $senderEmail, 'sender_name' => $senderName, @@ -3050,13 +3050,13 @@ public function sendTestEmail(string $email, array $emailSettings = []): array { ' ); - $this->logger->info('SoftwareCatalog: Email message created, attempting to send'); + $this->logger->info('Stackiq: Email message created, attempting to send'); // Send the email. $mailer->send($email); $this->logger->info( - 'SoftwareCatalog: Email sent successfully via Symfony Mailer', + 'Stackiq: Email sent successfully via Symfony Mailer', [ 'recipient' => $recipient, 'transport' => $transportType, @@ -3070,7 +3070,7 @@ public function sendTestEmail(string $email, array $emailSettings = []): array { ]; } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog: Failed to send test email', + 'Stackiq: Failed to send test email', [ 'recipient' => $email, 'exception_class' => get_class($e), @@ -3096,7 +3096,7 @@ public function sendTestEmail(string $email, array $emailSettings = []): array { */ public function testEmailConnection(array $emailSettings = []): array { $this->logger->info( - 'SoftwareCatalog: Starting email connection test', + 'Stackiq: Starting email connection test', [ 'has_email_settings' => empty($emailSettings) === false, ] @@ -3105,19 +3105,19 @@ public function testEmailConnection(array $emailSettings = []): array { try { // Ensure vendor autoloader is loaded. include_once __DIR__ . '/../../vendor/autoload.php'; - $this->logger->debug('SoftwareCatalog: Vendor autoloader loaded'); + $this->logger->debug('Stackiq: Vendor autoloader loaded'); // Use provided settings or fall back to stored settings. if (empty($emailSettings) === true) { $emailSettings = $this->getEmailSettings(); - $this->logger->info('SoftwareCatalog: Loaded email settings from storage'); + $this->logger->info('Stackiq: Loaded email settings from storage'); } else { - $this->logger->info('SoftwareCatalog: Using provided email settings'); + $this->logger->info('Stackiq: Using provided email settings'); } // Log the email configuration (without sensitive data). $this->logger->info( - 'SoftwareCatalog: Email configuration for connection test', + 'Stackiq: Email configuration for connection test', [ 'enabled' => $emailSettings['enabled'] ?? false, 'transport_type' => $emailSettings['transportType'] ?? 'unknown', @@ -3129,7 +3129,7 @@ public function testEmailConnection(array $emailSettings = []): array { // Check if email is enabled. if (($emailSettings['enabled'] ?? false) === false) { - $this->logger->warning('SoftwareCatalog: Email notifications are disabled'); + $this->logger->warning('Stackiq: Email notifications are disabled'); return [ 'success' => false, 'message' => 'Email notifications are disabled', @@ -3148,19 +3148,19 @@ public function testEmailConnection(array $emailSettings = []): array { } // Create transport based on configuration (this tests the connection). - $this->logger->info('SoftwareCatalog: Creating email transport for connection test'); + $this->logger->info('Stackiq: Creating email transport for connection test'); $transport = $this->createEmailTransport(emailSettings: $emailSettings); - $this->logger->info('SoftwareCatalog: Email transport created successfully'); + $this->logger->info('Stackiq: Email transport created successfully'); // Test the connection by creating a mailer instance. $mailer = new Mailer($transport); - $this->logger->info('SoftwareCatalog: Mailer instance created for connection test'); + $this->logger->info('Stackiq: Mailer instance created for connection test'); // For some transports, we can test the connection more directly. $connectionDetails = $this->getConnectionDetails(emailSettings: $emailSettings); $this->logger->info( - 'SoftwareCatalog: Email connection test completed successfully', + 'Stackiq: Email connection test completed successfully', [ 'transport' => $transportType, 'sender' => $senderEmail, @@ -3174,7 +3174,7 @@ public function testEmailConnection(array $emailSettings = []): array { ]; } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog: Email connection test failed', + 'Stackiq: Email connection test failed', [ 'exception_class' => get_class($e), 'exception_message' => $e->getMessage(), @@ -3289,7 +3289,7 @@ private function createEmailTransport(array $emailSettings): \Symfony\Component\ $transportType = $emailSettings['transportType'] ?? 'smtp'; $this->logger->info( - 'SoftwareCatalog: Creating transport', + 'Stackiq: Creating transport', [ 'transport_type' => $transportType, ] @@ -3297,14 +3297,14 @@ private function createEmailTransport(array $emailSettings): \Symfony\Component\ switch ($transportType) { case 'mailjet': - $this->logger->info('SoftwareCatalog: Creating Mailjet transport'); + $this->logger->info('Stackiq: Creating Mailjet transport'); return $this->createMailjetTransport(settings: $emailSettings); case 'smtp': - $this->logger->info('SoftwareCatalog: Creating SMTP transport'); + $this->logger->info('Stackiq: Creating SMTP transport'); return $this->createSmtpTransport(settings: $emailSettings); default: $this->logger->error( - 'SoftwareCatalog: Unsupported transport type', + 'Stackiq: Unsupported transport type', [ 'transport_type' => $transportType, ] @@ -3325,7 +3325,7 @@ private function createMailjetTransport(array $settings): \Symfony\Component\Mai $secretKey = $settings['mailjetSecretKey'] ?? ''; $this->logger->info( - 'SoftwareCatalog: Mailjet transport configuration', + 'Stackiq: Mailjet transport configuration', [ 'has_api_key' => empty($apiKey) === false, 'api_key_length' => strlen($apiKey), @@ -3336,7 +3336,7 @@ private function createMailjetTransport(array $settings): \Symfony\Component\Mai if (empty($apiKey) === true || empty($secretKey) === true) { $this->logger->error( - 'SoftwareCatalog: Mailjet API key and secret key are required', + 'Stackiq: Mailjet API key and secret key are required', [ 'api_key_empty' => empty($apiKey) === true, 'secret_key_empty' => empty($secretKey) === true, @@ -3352,7 +3352,7 @@ private function createMailjetTransport(array $settings): \Symfony\Component\Mai ); $this->logger->info( - 'SoftwareCatalog: Creating Mailjet transport with DSN', + 'Stackiq: Creating Mailjet transport with DSN', [ 'dsn_pattern' => 'mailjet+api://***:***@default', ] @@ -3361,7 +3361,7 @@ private function createMailjetTransport(array $settings): \Symfony\Component\Mai try { $transport = Transport::fromDsn($dsn); $this->logger->info( - 'SoftwareCatalog: Mailjet transport created successfully', + 'Stackiq: Mailjet transport created successfully', [ 'transport_class' => get_class($transport), ] @@ -3369,7 +3369,7 @@ private function createMailjetTransport(array $settings): \Symfony\Component\Mai return $transport; } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog: Failed to create Mailjet transport', + 'Stackiq: Failed to create Mailjet transport', [ 'exception_class' => get_class($e), 'exception_message' => $e->getMessage(), @@ -3394,7 +3394,7 @@ private function createSmtpTransport(array $settings): \Symfony\Component\Mailer $password = $settings['smtpPassword'] ?? ''; $this->logger->info( - 'SoftwareCatalog: SMTP transport configuration', + 'Stackiq: SMTP transport configuration', [ 'host' => $host, 'port' => $port, @@ -3425,7 +3425,7 @@ private function createSmtpTransport(array $settings): \Symfony\Component\Mailer $dsnPattern = sprintf('smtp://***:***@%s:%d%s', $host, $port, $encSuffix); $this->logger->info( - 'SoftwareCatalog: Creating SMTP transport with DSN', + 'Stackiq: Creating SMTP transport with DSN', [ 'dsn_pattern' => $dsnPattern, ] @@ -3434,7 +3434,7 @@ private function createSmtpTransport(array $settings): \Symfony\Component\Mailer try { $transport = Transport::fromDsn($dsn); $this->logger->info( - 'SoftwareCatalog: SMTP transport created successfully', + 'Stackiq: SMTP transport created successfully', [ 'transport_class' => get_class($transport), ] @@ -3442,7 +3442,7 @@ private function createSmtpTransport(array $settings): \Symfony\Component\Mailer return $transport; } catch (\Exception $e) { $this->logger->error( - 'SoftwareCatalog: Failed to create SMTP transport', + 'Stackiq: Failed to create SMTP transport', [ 'exception_class' => get_class($e), 'exception_message' => $e->getMessage(), @@ -3506,7 +3506,7 @@ private function shouldLoadSettings(): bool { public function getVersionInfo(): array { try { // Get the current app version. - $currentAppVersion = $this->appManager->getAppVersion(\OCA\SoftwareCatalog\AppInfo\Application::APP_ID); + $currentAppVersion = $this->appManager->getAppVersion(\OCA\Stackiq\AppInfo\Application::APP_ID); $this->logger->debug( 'SettingsService: Getting version information', @@ -3520,7 +3520,7 @@ public function getVersionInfo(): array { $storedConfigVersion = null; try { - $appId = \OCA\SoftwareCatalog\AppInfo\Application::APP_ID; + $appId = \OCA\Stackiq\AppInfo\Application::APP_ID; $storedConfigVersion = $configurationService->getConfiguredAppVersion($appId); } catch (\Exception $e) { $this->logger->warning( @@ -3550,7 +3550,7 @@ public function getVersionInfo(): array { } $versionInfo = [ - 'appName' => 'SoftwareCatalog', + 'appName' => 'Stackiq', 'appVersion' => $currentAppVersion, 'configuredVersion' => $storedConfigVersion, 'versionsMatch' => $versionsMatch, @@ -4612,7 +4612,7 @@ private function normalizeVoorzieningenConfig(array $input): array { public function getAmefConfig(): array { try { // Get ArchiMateService from container to avoid circular dependency. - $archiMateService = $this->container->get(\OCA\SoftwareCatalog\Service\ArchiMateService::class); + $archiMateService = $this->container->get(\OCA\Stackiq\Service\ArchiMateService::class); // Use reflection to access the private getAmefConfig method. // setAccessible() is unnecessary on PHP 8.1+ — private methods are @@ -4756,7 +4756,7 @@ public function setEmailConfig(array $config): void { public function getArchiMateStatus(): array { try { // Get ArchiMateService from container to avoid circular dependency. - $archiMateService = $this->container->get(\OCA\SoftwareCatalog\Service\ArchiMateService::class); + $archiMateService = $this->container->get(\OCA\Stackiq\Service\ArchiMateService::class); return $archiMateService->getArchiMateStatus(); } catch (\Exception $e) { @@ -4936,7 +4936,7 @@ private function getVoorzieningenObjectCounts(): array { private function getAmefObjectCounts(): array { try { // Get ArchiMateService from container to avoid circular dependency. - $archiMateService = $this->container->get(\OCA\SoftwareCatalog\Service\ArchiMateService::class); + $archiMateService = $this->container->get(\OCA\Stackiq\Service\ArchiMateService::class); // Get object counts using ArchiMateService methods. $elementObjects = $archiMateService->getElementObjects(); @@ -4997,7 +4997,7 @@ private function getAmefObjectCounts(): array { public function setArchiMateImportStatus(array $status): void { try { // Get ArchiMateService from container to avoid circular dependency. - $archiMateService = $this->container->get(\OCA\SoftwareCatalog\Service\ArchiMateService::class); + $archiMateService = $this->container->get(\OCA\Stackiq\Service\ArchiMateService::class); $archiMateService->setArchiMateImportStatus($status); } catch (\Exception $e) { @@ -5029,7 +5029,7 @@ public function setArchiMateImportStatus(array $status): void { public function setArchiMateExportStatus(array $status): void { try { // Get ArchiMateService from container to avoid circular dependency. - $archiMateService = $this->container->get(\OCA\SoftwareCatalog\Service\ArchiMateService::class); + $archiMateService = $this->container->get(\OCA\Stackiq\Service\ArchiMateService::class); $archiMateService->setArchiMateExportStatus($status); } catch (\Exception $e) { @@ -5059,7 +5059,7 @@ public function setArchiMateExportStatus(array $status): void { public function clearArchiMateImportStatus(): array { try { // Get ArchiMateService from container to avoid circular dependency. - $archiMateService = $this->container->get(\OCA\SoftwareCatalog\Service\ArchiMateService::class); + $archiMateService = $this->container->get(\OCA\Stackiq\Service\ArchiMateService::class); return $archiMateService->clearArchiMateImportStatus(); } catch (\Exception $e) { @@ -5097,7 +5097,7 @@ public function clearArchiMateImportStatus(): array { public function killArchiMateImport(): array { try { // Get ArchiMateService from container to avoid circular dependency. - $archiMateService = $this->container->get(\OCA\SoftwareCatalog\Service\ArchiMateService::class); + $archiMateService = $this->container->get(\OCA\Stackiq\Service\ArchiMateService::class); return $archiMateService->clearArchiMateImportStatus(true); // KillProcess = true. @@ -5135,7 +5135,7 @@ public function killArchiMateImport(): array { public function cancelArchiMateImport(): array { try { // Get ArchiMateService from container to avoid circular dependency. - $archiMateService = $this->container->get(\OCA\SoftwareCatalog\Service\ArchiMateService::class); + $archiMateService = $this->container->get(\OCA\Stackiq\Service\ArchiMateService::class); return $archiMateService->cancelArchiMateImport(); } catch (\Exception $e) { @@ -5174,7 +5174,7 @@ public function cancelArchiMateImport(): array { public function clearArchiMateExportStatus(): void { try { // Get ArchiMateService from container to avoid circular dependency. - $archiMateService = $this->container->get(\OCA\SoftwareCatalog\Service\ArchiMateService::class); + $archiMateService = $this->container->get(\OCA\Stackiq\Service\ArchiMateService::class); $archiMateService->clearArchiMateExportStatus(); } catch (\Exception $e) { @@ -6819,10 +6819,10 @@ private function getAvailableCronjobs(): array { return [ 'organization_contact_sync' => [ 'name' => 'Organization Contact Sync', - 'description' => 'Syncs organizations and contacts between SoftwareCatalog and OpenRegister.', + 'description' => 'Syncs organizations and contacts between Stackiq and OpenRegister.', 'interval' => 300, // 5 minutes. - 'class' => 'OCA\\SoftwareCatalog\\BackgroundJob\\OrganizationContactSyncJob', + 'class' => 'OCA\\Stackiq\\BackgroundJob\\OrganizationContactSyncJob', ], ]; }//end getAvailableCronjobs() @@ -7234,7 +7234,7 @@ public function setEolSyncStatus(array $status): void { * merged by key union (recursing on shared keys); list arrays are concatenated; * scalars in the fragment overwrite the base. Disjoint fragments never collide. * - * EXCEPTION (catalog-ratings, softwarecatalog#375): any key literally named + * EXCEPTION (catalog-ratings, stackiq#375): any key literally named * `authorization` switches its entire subtree to REPLACE semantics for list * values, instead of the general concatenation above. Concatenating an RBAC * rule list is a fail-OPEN trap: if the base already carries an unconditional @@ -7262,7 +7262,7 @@ public function setEolSyncStatus(array $status): void { * an `authorization` key has been crossed, and it stays true for that whole subtree. Turning * it into two methods would mean duplicating the merge for the sole purpose of removing a * parameter that no external caller ever passes, and would make the fail-open trap this flag - * exists to close (softwarecatalog#375) easier to reintroduce. + * exists to close (stackiq#375) easier to reintroduce. */ private static function deepMergeConfig(array $base, array $overlay, bool $replaceLists = false): array { foreach ($overlay as $key => $value) { diff --git a/lib/Service/SoftwareCatalogue/ApiClient.php b/lib/Service/Stackiq/ApiClient.php similarity index 91% rename from lib/Service/SoftwareCatalogue/ApiClient.php rename to lib/Service/Stackiq/ApiClient.php index baad662f..f46597a6 100644 --- a/lib/Service/SoftwareCatalogue/ApiClient.php +++ b/lib/Service/Stackiq/ApiClient.php @@ -1,13 +1,13 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -21,15 +21,15 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\SoftwareCatalogue; +namespace OCA\Stackiq\Service\Stackiq; use OCA\OpenRegister\Contract\ObjectServiceInterface; use Psr\Log\LoggerInterface; /** - * Handles all API communication for the SoftwareCatalogue domain. + * Handles all API communication for the Stackiq domain. * - * SoftwareCatalogueService delegates API fetch operations to this class, + * StackiqService delegates API fetch operations to this class, * keeping its own constructor coupling below the PHPMD CouplingBetweenObjects * threshold and keeping its methods below ExcessiveMethodLength. * diff --git a/lib/Service/SoftwareCatalogue/ConflictResolver.php b/lib/Service/Stackiq/ConflictResolver.php similarity index 92% rename from lib/Service/SoftwareCatalogue/ConflictResolver.php rename to lib/Service/Stackiq/ConflictResolver.php index 92506ff3..0a044f64 100644 --- a/lib/Service/SoftwareCatalogue/ConflictResolver.php +++ b/lib/Service/Stackiq/ConflictResolver.php @@ -1,13 +1,13 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -21,14 +21,14 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\SoftwareCatalogue; +namespace OCA\Stackiq\Service\Stackiq; use Psr\Log\LoggerInterface; /** - * Resolves conflicts and deduplicates entries in the SoftwareCatalogue domain. + * Resolves conflicts and deduplicates entries in the Stackiq domain. * - * SoftwareCatalogueService delegates all conflict detection and resolution + * StackiqService delegates all conflict detection and resolution * methods to this class, shrinking its own complexity metrics. * * @spec openspec/changes/method-decomposition/tasks.md#task-2 diff --git a/lib/Service/SoftwareCatalogue/ContactPersonHandler.php b/lib/Service/Stackiq/ContactPersonHandler.php similarity index 98% rename from lib/Service/SoftwareCatalogue/ContactPersonHandler.php rename to lib/Service/Stackiq/ContactPersonHandler.php index cae6758a..3e0395cd 100644 --- a/lib/Service/SoftwareCatalogue/ContactPersonHandler.php +++ b/lib/Service/Stackiq/ContactPersonHandler.php @@ -7,7 +7,7 @@ * contact processing, and organizational hierarchy management. * * @category Handler - * @package OCA\SoftwareCatalog\Service\SoftwareCatalogue + * @package OCA\Stackiq\Service\Stackiq * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -16,9 +16,9 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\SoftwareCatalogue; +namespace OCA\Stackiq\Service\Stackiq; -use OCA\SoftwareCatalog\Service\SymfonyEmailService; +use OCA\Stackiq\Service\SymfonyEmailService; use OCP\App\IAppManager; use OCP\IAppConfig; use OCP\IConfig; @@ -33,7 +33,7 @@ * Handler for contact person-related operations. * * @category Handler - * @package OCA\SoftwareCatalog\Service\SoftwareCatalogue + * @package OCA\Stackiq\Service\Stackiq * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -302,7 +302,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->debug( 'User account creation started', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactId, 'email' => $email, 'organizationUuid' => $organizationUuid, @@ -314,7 +314,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->error( '❌ USER CREATION FAILED - NO EMAIL', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactpersoonId' => $contactId, ] ); @@ -335,7 +335,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->critical( '📝 USERNAME GENERATED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactId, 'generatedUsername' => $username, 'email' => $email, @@ -354,7 +354,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->critical( '♻️ USER EXISTS BY EMAIL', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'email' => $email, 'contactpersoonId' => $contactId, ] @@ -376,7 +376,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->critical( '✅ EXISTING USER UPDATED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'username' => $existingUser->getUID(), 'email' => $email, 'organizationUuid' => $organizationUuid, @@ -399,7 +399,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->critical( '♻️ USER EXISTS BY USERNAME', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'username' => $username, 'contactpersoonId' => $contactId, ] @@ -423,7 +423,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->critical( '✅ EXISTING USER UPDATED BY USERNAME', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'username' => $username, 'email' => $existingUserByUsername->getEMailAddress(), 'organizationUuid' => $organizationUuid, @@ -437,7 +437,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->critical( '🚀 CREATING NEW USER ACCOUNT', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'username' => $username, 'email' => $email, 'contactId' => $contactId, @@ -455,7 +455,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->critical( '🎊 NEW USER ACCOUNT CREATED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'username' => $username, 'email' => $email, 'contactId' => $contactId, @@ -485,7 +485,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->critical( '📋 USER DETAILS SET', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'username' => $username, 'email' => $email, 'displayName' => $displayName, @@ -558,7 +558,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->critical( '🎉 USER ACCOUNT CREATION COMPLETED', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactpersoonId' => $contactId, 'username' => $username, 'email' => $email, @@ -574,7 +574,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->error( '❌ USER CREATION RETURNED NULL', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'username' => $username, 'email' => $email, 'contactpersoonId' => $contactId, @@ -587,7 +587,7 @@ public function createUserAccount(object $contactPersonObject, bool $isFirstCont $this->_logger->error( '💥 USER CREATION EXCEPTION', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactpersoonId' => $contactPersonObject->getId(), 'email' => $objectData['email'] ?? $objectData['e-mailadres'] ?? 'unknown', 'username' => $username ?? 'unknown', @@ -640,7 +640,7 @@ private function assignUserGroups(\OCP\IUser $user, array $objectData, bool $isF } // Get the settings service to access group configurations. - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); // Add user to organization admin groups if this is the first contact. if ($isFirstContact === true) { @@ -995,7 +995,7 @@ private function getOrganizationGroup(string $organizationId): ?\OCP\IGroup { } // Get register and schema IDs dynamically from configuration. - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $registerId = $settingsService->getVoorzieningenRegisterId(); $organisationSchemaId = $settingsService->getSchemaIdForObjectType('organization'); @@ -1046,7 +1046,7 @@ public function isFirstContactForOrganization(object $contactObject, array $obje $this->_logger->info( 'isFirstContactForOrganization: Defaulting to true (simplified)', [ - 'app' => 'softwarecatalog', + 'app' => 'stackiq', 'contactId' => $contactObject->getId(), 'contactUuid' => $contactObject->getUuid(), ] @@ -1475,7 +1475,7 @@ public function setUserManager(string $username, string $managerUsername): void // Since there's no built-in manager field, we'll use preferences. $this->config->setUserValue( $username, - 'softwarecatalog', + 'stackiq', 'manager', $managerUsername ); @@ -1511,7 +1511,7 @@ public function getUserManager(string $username): ?string { try { $manager = $this->config->getUserValue( $username, - 'softwarecatalog', + 'stackiq', 'manager', '' ); @@ -1553,7 +1553,7 @@ private function getOrganizationType(string $organizationId): string { ); // Get voorzieningen config for register and schema. - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $voorzieningenConfig = $settingsService->getVoorzieningenConfig(); $register = $voorzieningenConfig['register'] ?? ''; $organizationSchema = $voorzieningenConfig['organisatie_schema'] ?? ''; @@ -1667,7 +1667,7 @@ private function sendUserCreationEmail(\OCP\IUser $user, array $objectData): voi try { $objectService = $this->getObjectService(); // Get register and schema IDs dynamically from configuration. - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $registerId = $settingsService->getVoorzieningenRegisterId(); $organisationSchemaId = $settingsService->getSchemaIdForObjectType('organization'); @@ -2116,7 +2116,7 @@ public function shouldAddContactpersoonToOrganization(object $contactPersonObjec } // Get the organization object. - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $registerId = $settingsService->getVoorzieningenRegisterId(); $organisationSchemaId = $settingsService->getSchemaIdForObjectType('organization'); @@ -2199,7 +2199,7 @@ public function addContactpersoonToOrganization(object $contactPersonObject): bo } // Get the organization object. - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $registerId = $settingsService->getVoorzieningenRegisterId(); $organisationSchemaId = $settingsService->getSchemaIdForObjectType('organization'); @@ -2502,7 +2502,7 @@ private function ensureOrganizationEntity(string $organizationUuid): ?\OCA\OpenR $objectService = $this->getObjectService(); // Get voorzieningen config for register and schema. - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $voorzieningenConfig = $settingsService->getVoorzieningenConfig(); $register = $voorzieningenConfig['register'] ?? ''; $organizationSchema = $voorzieningenConfig['organisatie_schema'] ?? ''; diff --git a/lib/Service/SoftwareCatalogue/DataMapper.php b/lib/Service/Stackiq/DataMapper.php similarity index 93% rename from lib/Service/SoftwareCatalogue/DataMapper.php rename to lib/Service/Stackiq/DataMapper.php index d5049240..ead69b56 100644 --- a/lib/Service/SoftwareCatalogue/DataMapper.php +++ b/lib/Service/Stackiq/DataMapper.php @@ -1,13 +1,13 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -21,14 +21,14 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\SoftwareCatalogue; +namespace OCA\Stackiq\Service\Stackiq; use Psr\Log\LoggerInterface; /** - * Maps and transforms data between external API formats and the SoftwareCatalogue domain model. + * Maps and transforms data between external API formats and the Stackiq domain model. * - * SoftwareCatalogueService delegates all data transformation methods to this class, + * StackiqService delegates all data transformation methods to this class, * shrinking its own method bodies below ExcessiveMethodLength. * * @spec openspec/changes/method-decomposition/tasks.md#task-2 diff --git a/lib/Service/SoftwareCatalogue/GroupHandler.php b/lib/Service/Stackiq/GroupHandler.php similarity index 98% rename from lib/Service/SoftwareCatalogue/GroupHandler.php rename to lib/Service/Stackiq/GroupHandler.php index aa48e2f3..1bc340a4 100644 --- a/lib/Service/SoftwareCatalogue/GroupHandler.php +++ b/lib/Service/Stackiq/GroupHandler.php @@ -7,7 +7,7 @@ * and ensures all required groups exist and are properly configured. * * @category Handler - * @package OCA\SoftwareCatalog\Service\SoftwareCatalogue + * @package OCA\Stackiq\Service\Stackiq * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -19,7 +19,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\SoftwareCatalogue; +namespace OCA\Stackiq\Service\Stackiq; use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCP\App\IAppManager; @@ -36,7 +36,7 @@ * Handler for group management operations * * @category Handler - * @package OCA\SoftwareCatalog\Service\SoftwareCatalogue + * @package OCA\Stackiq\Service\Stackiq * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -57,7 +57,7 @@ class GroupHandler { * * @var string */ - private const APP_NAME = 'softwarecatalog'; + private const APP_NAME = 'stackiq'; /** * GroupHandler constructor @@ -396,7 +396,7 @@ public function updateOrganizationGroups(IUser $user, array $objectData): void { */ private function resolveOrganisationData(string $organisationUuid): ?array { $objectService = $this->getObjectService(); - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $registerId = $settingsService->getVoorzieningenRegisterId(); $organisationSchemaId = $settingsService->getSchemaIdForObjectType('organization'); diff --git a/lib/Service/SoftwareCatalogue/HierarchyHandler.php b/lib/Service/Stackiq/HierarchyHandler.php similarity index 98% rename from lib/Service/SoftwareCatalogue/HierarchyHandler.php rename to lib/Service/Stackiq/HierarchyHandler.php index efd6eb00..86916186 100644 --- a/lib/Service/SoftwareCatalogue/HierarchyHandler.php +++ b/lib/Service/Stackiq/HierarchyHandler.php @@ -7,7 +7,7 @@ * and manager relationships within organizations. * * @category Handler - * @package OCA\SoftwareCatalog\Service\SoftwareCatalogue + * @package OCA\Stackiq\Service\Stackiq * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -19,7 +19,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\SoftwareCatalogue; +namespace OCA\Stackiq\Service\Stackiq; use OCP\IGroupManager; use OCP\IUserManager; @@ -29,7 +29,7 @@ * Handler for organizational hierarchy management * * @category Handler - * @package OCA\SoftwareCatalog\Service\SoftwareCatalogue + * @package OCA\Stackiq\Service\Stackiq * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 diff --git a/lib/Service/SoftwareCatalogue/OrganizationHandler.php b/lib/Service/Stackiq/OrganizationHandler.php similarity index 98% rename from lib/Service/SoftwareCatalogue/OrganizationHandler.php rename to lib/Service/Stackiq/OrganizationHandler.php index 25533b53..9520223f 100644 --- a/lib/Service/SoftwareCatalogue/OrganizationHandler.php +++ b/lib/Service/Stackiq/OrganizationHandler.php @@ -7,7 +7,7 @@ * organization processing, and hierarchy management. * * @category Handler - * @package OCA\SoftwareCatalog\Service\SoftwareCatalogue + * @package OCA\Stackiq\Service\Stackiq * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -19,7 +19,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service\SoftwareCatalogue; +namespace OCA\Stackiq\Service\Stackiq; use OCP\App\IAppManager; use OCP\IGroup; @@ -33,7 +33,7 @@ * Handler for organization-related operations. * * @category Handler - * @package OCA\SoftwareCatalog\Service\SoftwareCatalogue + * @package OCA\Stackiq\Service\Stackiq * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -181,7 +181,7 @@ public function ensureOrganizationGroup(object $organizationObject, array &$obje // Save the updated organization with correct register/schema IDs. $objectService = $this->getObjectService(); - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $registerId = $settingsService->getVoorzieningenRegisterId(); $organizationSchemaId = $settingsService->getSchemaIdForObjectType('organization'); @@ -347,7 +347,7 @@ public function processContactpersonen(object $organizationObject): array { foreach ($contactpersonen as $index => $contactPerson) { try { // Get the contactgegevens schema ID from settings. - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $contactgegevensSchemaId = $settingsService->getSchemaIdForObjectType('contactgegevens'); $registerId = $settingsService->getVoorzieningenRegisterId(); diff --git a/lib/Service/SoftwareCatalogContactSyncService.php b/lib/Service/StackiqContactSyncService.php similarity index 94% rename from lib/Service/SoftwareCatalogContactSyncService.php rename to lib/Service/StackiqContactSyncService.php index 324a3606..6e2cc4e7 100644 --- a/lib/Service/SoftwareCatalogContactSyncService.php +++ b/lib/Service/StackiqContactSyncService.php @@ -1,9 +1,9 @@ * @copyright 2026 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -25,32 +25,31 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCP\Constants; use OCP\Contacts\IManager as IContactsManager; use Psr\Log\LoggerInterface; -use RuntimeException; /** - * Search, import and create Nextcloud contacts for softwarecatalog + * Search, import and create Nextcloud contacts for stackiq * relationship/role records. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: * @link https://codeberg.org/Conduction/SoftwareCatalog * * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) Overall complexity 56 (threshold 50). The - * class maps several distinct softwarecatalog relationship types (organisation, contactpersoon, + * class maps several distinct stackiq relationship types (organisation, contactpersoon, * …) onto Nextcloud's vCard contact model, and each mapping needs per-field presence checks * because the legacy identity fields are optional and inconsistently populated across records. * The Contacts API is also an optional dependency, so every entry point carries an availability * guard. Both are breadth of mapping rather than depth of logic. */ -class SoftwareCatalogContactSyncService { +class StackiqContactSyncService { /** * Constructor. * @@ -143,7 +142,7 @@ public function searchContacts(string $query): array { */ public function syncToContacts(string $objectType, array $record): ?string { if ($this->isAvailable() === false) { - $this->logger->info('[SoftwareCatalogContactSync] Contacts disabled, cannot resolve UID', ['objectType' => $objectType]); + $this->logger->info('[StackiqContactSync] Contacts disabled, cannot resolve UID', ['objectType' => $objectType]); return null; } @@ -257,7 +256,7 @@ public function createContactForRecord(string $objectType, array $record): ?stri $addressBookKey = $this->firstWritableAddressBookKey(); if ($addressBookKey === null) { $this->logger->warning( - '[SoftwareCatalogContactSync] No writable addressbook available; cannot create contact', + '[StackiqContactSync] No writable addressbook available; cannot create contact', ['objectType' => $objectType] ); return null; @@ -265,7 +264,7 @@ public function createContactForRecord(string $objectType, array $record): ?stri $properties = $this->recordToVCard(objectType: $objectType, record: $record); if (($properties['FN'] ?? '') === '') { - $this->logger->warning('[SoftwareCatalogContactSync] Record has no identity to create a contact from', ['objectType' => $objectType]); + $this->logger->warning('[StackiqContactSync] Record has no identity to create a contact from', ['objectType' => $objectType]); return null; } diff --git a/lib/Service/SoftwareCatalogueService.php b/lib/Service/StackiqService.php similarity index 83% rename from lib/Service/SoftwareCatalogueService.php rename to lib/Service/StackiqService.php index 307d78f2..bf035ad0 100644 --- a/lib/Service/SoftwareCatalogueService.php +++ b/lib/Service/StackiqService.php @@ -7,7 +7,7 @@ * user management, contact processing, and object lifecycle management. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -18,12 +18,12 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\ContactPersonHandler; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\GroupHandler; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\HierarchyHandler; -use OCA\SoftwareCatalog\Service\SoftwareCatalogue\OrganizationHandler; +use OCA\Stackiq\Service\Stackiq\ContactPersonHandler; +use OCA\Stackiq\Service\Stackiq\GroupHandler; +use OCA\Stackiq\Service\Stackiq\HierarchyHandler; +use OCA\Stackiq\Service\Stackiq\OrganizationHandler; use OCP\App\IAppManager; use OCP\IGroupManager; use OCP\IUserManager; @@ -39,7 +39,7 @@ * email notifications, and object lifecycle management. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -65,7 +65,7 @@ * @SuppressWarnings(PHPMD.UndefinedVariable) * @SuppressWarnings(PHPMD.CountInLoopExpression) */ -class SoftwareCatalogueService { +class StackiqService { /** * The name of the app @@ -75,7 +75,7 @@ class SoftwareCatalogueService { private string $appName; /** - * SoftwareCatalogueService constructor + * StackiqService constructor * * @param OrganizationHandler $_organizationHandler Organization handler. * @param ContactPersonHandler $_contactPersonHandler Contact person handler. @@ -102,7 +102,7 @@ public function __construct( private readonly IUserManager $_userManager, private readonly IGroupManager $_groupManager, ) { - $this->appName = 'softwarecatalog'; + $this->appName = 'stackiq'; }//end __construct() /** @@ -190,7 +190,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat $objectData = $contactPersonObject->getObject(); $this->_logger->info( - 'SoftwareCatalogueService: Starting contactpersoon processing', + 'StackiqService: Starting contactpersoon processing', [ 'objectId' => $objectId, 'objectData' => $objectData, @@ -200,7 +200,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat // Delegate to contact person handler. $this->_logger->debug( - 'SoftwareCatalogueService: Delegating to ContactPersonHandler for contactpersoon processing', + 'StackiqService: Delegating to ContactPersonHandler for contactpersoon processing', [ 'objectId' => $objectId, ] @@ -209,7 +209,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat $result = $this->_contactPersonHandler->processContactpersoon($contactPersonObject, $isUpdate); $this->_logger->info( - 'SoftwareCatalogueService: ContactPersonHandler processing completed', + 'StackiqService: ContactPersonHandler processing completed', [ 'objectId' => $objectId, 'result' => $result, @@ -223,7 +223,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat $username = $updatedObjectData['username'] ?? ''; $this->_logger->info( - 'SoftwareCatalogueService: Username extracted from processed object', + 'StackiqService: Username extracted from processed object', [ 'objectId' => $objectId, 'username' => $username, @@ -237,7 +237,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat // as it would overwrite the correct group assignments. // Ensure organization has beheerder and set up manager relationships. $this->_logger->debug( - 'SoftwareCatalogueService: Ensuring organization beheerder', + 'StackiqService: Ensuring organization beheerder', [ 'objectId' => $objectId, 'username' => $username, @@ -248,7 +248,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat // Set user to inactive initially. $this->_logger->debug( - 'SoftwareCatalogueService: Setting user to inactive', + 'StackiqService: Setting user to inactive', [ 'objectId' => $objectId, 'username' => $username, @@ -258,7 +258,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat $this->_contactPersonHandler->setUserInactive($username); $this->_logger->info( - 'SoftwareCatalogueService: User setup completed', + 'StackiqService: User setup completed', [ 'objectId' => $objectId, 'username' => $username, @@ -270,7 +270,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat $organization = $objectData['organization'] ?? null; if (empty($organization) === false) { $this->_logger->info( - 'SoftwareCatalogueService: Adding user to organization entity', + 'StackiqService: Adding user to organization entity', [ 'objectId' => $objectId, 'username' => $username, @@ -282,7 +282,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat $organisationMapper = $this->getOrganisationMapper(); if ($organisationMapper === null) { $this->_logger->warning( - 'SoftwareCatalogueService: OpenRegister OrganisationMapper not available, skipping organization membership', + 'StackiqService: OpenRegister OrganisationMapper not available, skipping organization membership', [ 'objectId' => $objectId, 'username' => $username, @@ -304,7 +304,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat $organisationMapper->save($organisation); $this->_logger->info( - 'SoftwareCatalogueService: Successfully added user to organization entity', + 'StackiqService: Successfully added user to organization entity', [ 'objectId' => $objectId, 'username' => $username, @@ -314,7 +314,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat ); } else { $this->_logger->info( - 'SoftwareCatalogueService: User already in organization entity', + 'StackiqService: User already in organization entity', [ 'objectId' => $objectId, 'username' => $username, @@ -324,7 +324,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat }//end if } else { $this->_logger->warning( - 'SoftwareCatalogueService: Organization entity not found', + 'StackiqService: Organization entity not found', [ 'objectId' => $objectId, 'username' => $username, @@ -334,7 +334,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat }//end if } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to add user to organization entity', + 'StackiqService: Failed to add user to organization entity', [ 'objectId' => $objectId, 'username' => $username, @@ -345,7 +345,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat }//end try } else { $this->_logger->warning( - 'SoftwareCatalogueService: No organisation reference found for contact person', + 'StackiqService: No organisation reference found for contact person', [ 'objectId' => $objectId, 'username' => $username, @@ -354,7 +354,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat }//end if } else { $this->_logger->warning( - 'SoftwareCatalogueService: No username generated for contactpersoon', + 'StackiqService: No username generated for contactpersoon', [ 'objectId' => $objectId, 'objectData' => $updatedObjectData, @@ -363,7 +363,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat }//end if } else { $this->_logger->warning( - 'SoftwareCatalogueService: ContactPersonHandler returned false', + 'StackiqService: ContactPersonHandler returned false', [ 'objectId' => $objectId, 'processingTime' => round((microtime(true) - $startTime) * 1000, 2) . 'ms', @@ -374,7 +374,7 @@ public function processContactpersoon(object $contactPersonObject, bool $isUpdat return $result; } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to process contactpersoon object: ' . $e->getMessage(), + 'StackiqService: Failed to process contactpersoon object: ' . $e->getMessage(), [ 'exception' => $e->getMessage(), 'file' => $e->getFile(), @@ -483,7 +483,7 @@ public function getUserManager(string $username): ?string { public function handleNewOrganization(object $organizationObject): void { try { $this->_logger->info( - 'SoftwareCatalogueService: Handling new organization', + 'StackiqService: Handling new organization', [ 'objectId' => $organizationObject->getId(), ] @@ -494,7 +494,7 @@ public function handleNewOrganization(object $organizationObject): void { if ($syncResult === true) { $this->_logger->info( - 'SoftwareCatalogueService: Successfully synced organization with OpenRegister', + 'StackiqService: Successfully synced organization with OpenRegister', [ 'objectId' => $organizationObject->getId(), ] @@ -504,7 +504,7 @@ public function handleNewOrganization(object $organizationObject): void { $this->updateOrganizationReferences(organizationObject: $organizationObject); } else { $this->_logger->warning( - 'SoftwareCatalogueService: Failed to sync organization with OpenRegister', + 'StackiqService: Failed to sync organization with OpenRegister', [ 'objectId' => $organizationObject->getId(), ] @@ -554,7 +554,7 @@ public function handleNewOrganization(object $organizationObject): void { $contactpersonen = $objectData['contactpersonen'] ?? []; if (empty($contactpersonen) === false) { $this->_logger->info( - 'SoftwareCatalogueService: Processing nested contact persons', + 'StackiqService: Processing nested contact persons', [ 'objectId' => $organizationObject->getId(), 'contactPersonCount' => count($contactpersonen), @@ -565,19 +565,19 @@ public function handleNewOrganization(object $organizationObject): void { $objectService = $this->getObjectService(); if (empty($objectService) === false) { - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $voorzieningenConfig = $settingsService->getVoorzieningenConfig(); $contactSchemaId = $voorzieningenConfig['contactpersoon_schema'] ?? null; if ($contactSchemaId === null) { - $this->_logger->warning('SoftwareCatalogueService: Missing contactpersoon schema configuration'); + $this->_logger->warning('StackiqService: Missing contactpersoon schema configuration'); return; } $organisationMapper = $this->getOrganisationMapper(); if ($organisationMapper === null) { $this->_logger->warning( - 'SoftwareCatalogueService: OpenRegister OrganisationMapper not available, skipping contact person membership' + 'StackiqService: OpenRegister OrganisationMapper not available, skipping contact person membership' ); return; } @@ -599,7 +599,7 @@ public function handleNewOrganization(object $organizationObject): void { $addedUsers[] = $email; $this->_logger->info( - 'SoftwareCatalogueService: Added nested contact person user to organization', + 'StackiqService: Added nested contact person user to organization', [ 'objectId' => $organizationObject->getId(), 'contactPersonId' => $contactPersonId, @@ -610,7 +610,7 @@ public function handleNewOrganization(object $organizationObject): void { } } catch (\Exception $e) { $this->_logger->warning( - 'SoftwareCatalogueService: Failed to process nested contact person', + 'StackiqService: Failed to process nested contact person', [ 'objectId' => $organizationObject->getId(), 'contactPersonId' => $contactPersonId, @@ -625,7 +625,7 @@ public function handleNewOrganization(object $organizationObject): void { $organisationMapper->save($organisation); $this->_logger->info( - 'SoftwareCatalogueService: Updated org with nested contact person users', + 'StackiqService: Updated org with nested contact person users', [ 'objectId' => $organizationObject->getId(), 'organizationUuid' => $organizationUuid, @@ -645,7 +645,7 @@ public function handleNewOrganization(object $organizationObject): void { $this->syncContactPersonUsernamesWithOrganization(organizationUuid: $organizationUuid); $this->_logger->info( - 'SoftwareCatalogueService: Completed final contact person synchronization for new organization', + 'StackiqService: Completed final contact person synchronization for new organization', [ 'objectId' => $organizationObject->getId(), 'organizationUuid' => $organizationUuid, @@ -653,7 +653,7 @@ public function handleNewOrganization(object $organizationObject): void { ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to handle new organization: ' . $e->getMessage(), + 'StackiqService: Failed to handle new organization: ' . $e->getMessage(), [ 'objectId' => $organizationObject->getId(), 'exception' => $e->getMessage(), @@ -677,7 +677,7 @@ public function handleNewOrganization(object $organizationObject): void { public function handleOrganizationUpdate(object $organizationObject, object $oldOrganizationObject): void { try { $this->_logger->info( - 'SoftwareCatalogueService: Handling organization update', + 'StackiqService: Handling organization update', [ 'objectId' => $organizationObject->getId(), ] @@ -695,14 +695,14 @@ public function handleOrganizationUpdate(object $organizationObject, object $old if ($syncResult === true) { $this->_logger->info( - 'SoftwareCatalogueService: Successfully synced organization with OpenRegister', + 'StackiqService: Successfully synced organization with OpenRegister', [ 'objectId' => $organizationObject->getId(), ] ); } else { $this->_logger->warning( - 'SoftwareCatalogueService: Failed to sync organization with OpenRegister', + 'StackiqService: Failed to sync organization with OpenRegister', [ 'objectId' => $organizationObject->getId(), ] @@ -736,7 +736,7 @@ public function handleOrganizationUpdate(object $organizationObject, object $old $organizationUuid = $newData['id'] ?? $organizationObject->getId(); $this->_logger->info( - 'SoftwareCatalogueService: Organization became active - creating users from contactpersonen', + 'StackiqService: Organization became active - creating users from contactpersonen', [ 'organizationUuid' => $organizationUuid, ] @@ -747,8 +747,8 @@ public function handleOrganizationUpdate(object $organizationObject, object $old // and contactpersonen were added before activation. $this->processOrganization(organizationObject: $organizationObject); - // Activate SoftwareCatalog-specific users in this organization. - $this->activateSoftwareCatalogUsersForOrganization(organizationUuid: $organizationUuid); + // Activate Stackiq-specific users in this organization. + $this->activateStackiqUsersForOrganization(organizationUuid: $organizationUuid); // Send activation email. try { @@ -792,14 +792,14 @@ public function handleOrganizationUpdate(object $organizationObject, object $old ); if ($becameInactive === true) { - // Deactivate SoftwareCatalog-specific users in this organization. + // Deactivate Stackiq-specific users in this organization. $organizationUuid = $newData['id'] ?? $organizationObject->getId(); - $this->deactivateSoftwareCatalogUsersForOrganization(organizationUuid: $organizationUuid); + $this->deactivateStackiqUsersForOrganization(organizationUuid: $organizationUuid); } }//end if } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to handle organization update: ' . $e->getMessage(), + 'StackiqService: Failed to handle organization update: ' . $e->getMessage(), [ 'objectId' => $organizationObject->getId(), 'exception' => $e->getMessage(), @@ -892,7 +892,7 @@ public function handleNewGebruiker(object $userObject): void { * * Its whole body was a `logger->info('Sending gebruiker welcome email')` * — it never sent anything — and no caller reached it: - * `SoftwareCatalogEventListener` does not invoke it on the + * `StackiqEventListener` does not invoke it on the * gebruiker-created path. Wiring a method that sends no mail would have * bought nothing; implementing one is a feature, not dead-code removal. */ @@ -1002,7 +1002,7 @@ public function restoreUserAccessForGebruiker(object $userObject): void { * `syncUserWithRevertedContact()` and `updateUserFromRevertedGebruiker()` * were the same shape as `sendGebruikerWelcomeEmail()` above: a single * `logger->info()` and nothing else, with no caller — - * `SoftwareCatalogEventListener` handles `ObjectRevertedEvent` without + * `StackiqEventListener` handles `ObjectRevertedEvent` without * touching this service. They named a capability (reconcile the Nextcloud * user after an object revert) that has never been implemented; a log line * is not that capability, and wiring one in would have made the gap @@ -1076,7 +1076,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object try { $objectId = $contactPersonObject->getId(); $this->_logger->info( - 'SoftwareCatalogueService: Starting contactpersoon update handling', + 'StackiqService: Starting contactpersoon update handling', [ 'objectId' => $objectId, 'hasOldObject' => $oldContactPersonObject !== null, @@ -1095,7 +1095,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object $oldRoles = $oldData['roles'] ?? []; $this->_logger->debug( - 'SoftwareCatalogueService: Comparing roles for contactpersoon update', + 'StackiqService: Comparing roles for contactpersoon update', [ 'objectId' => $objectId, 'newRoles' => $newRoles, @@ -1109,7 +1109,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object if (is_array($newRoles) === false) { $newRoles = [$newRoles]; $this->_logger->debug( - 'SoftwareCatalogueService: Converted newRoles to array', + 'StackiqService: Converted newRoles to array', [ 'objectId' => $objectId, 'newRoles' => $newRoles, @@ -1120,7 +1120,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object if (is_array($oldRoles) === false) { $oldRoles = [$oldRoles]; $this->_logger->debug( - 'SoftwareCatalogueService: Converted oldRoles to array', + 'StackiqService: Converted oldRoles to array', [ 'objectId' => $objectId, 'oldRoles' => $oldRoles, @@ -1132,7 +1132,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object if ($newRoles !== $oldRoles) { // Roles changed - use role-based group assignment instead of generic group assignment. $this->_logger->info( - 'SoftwareCatalogueService: Roles changed for contactpersoon, using role-based group assignment', + 'StackiqService: Roles changed for contactpersoon, using role-based group assignment', [ 'contactpersoonId' => $objectId, 'oldRoles' => $oldRoles, @@ -1161,7 +1161,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object $this->_contactPersonHandler->updateUserGroupsFromContactData($user, $contactData); $this->_logger->info( - 'SoftwareCatalogueService: Organization type-based group updates completed', + 'StackiqService: Organization type-based group updates completed', [ 'username' => $username, 'objectId' => $objectId, @@ -1170,7 +1170,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object ); } else { $this->_logger->warning( - 'SoftwareCatalogueService: User not found for role-based group updates', + 'StackiqService: User not found for role-based group updates', [ 'username' => $username, 'objectId' => $objectId, @@ -1179,7 +1179,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object }//end if } else { $this->_logger->warning( - 'SoftwareCatalogueService: No username available for role-based group updates', + 'StackiqService: No username available for role-based group updates', [ 'objectId' => $objectId, 'newData' => $newData, @@ -1189,7 +1189,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object } else { // No role changes - use standard processing (assigns generic groups). $this->_logger->debug( - 'SoftwareCatalogueService: No role changes, using standard contactpersoon processing', + 'StackiqService: No role changes, using standard contactpersoon processing', [ 'objectId' => $objectId, 'roles' => $newRoles, @@ -1199,7 +1199,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object $result = $this->processContactpersoon(contactPersonObject: $contactPersonObject, isUpdate: true); $this->_logger->info( - 'SoftwareCatalogueService: Standard contactpersoon processing completed', + 'StackiqService: Standard contactpersoon processing completed', [ 'objectId' => $objectId, 'result' => $result, @@ -1209,7 +1209,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object }//end if $this->_logger->info( - 'SoftwareCatalogueService: Contactpersoon update handling completed', + 'StackiqService: Contactpersoon update handling completed', [ 'objectId' => $objectId, 'totalProcessingTime' => round((microtime(true) - $startTime) * 1000, 2) . 'ms', @@ -1217,7 +1217,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to handle contactpersoon update: ' . $e->getMessage(), + 'StackiqService: Failed to handle contactpersoon update: ' . $e->getMessage(), [ 'objectId' => $contactPersonObject->getId(), 'exception' => $e->getMessage(), @@ -1241,7 +1241,7 @@ public function handleContactpersoonUpdate(object $contactPersonObject, ?object public function handleOrganizationDeletion(object $organizationObject): void { try { $this->_logger->info( - 'SoftwareCatalogueService: Handling organization deletion', + 'StackiqService: Handling organization deletion', [ 'objectId' => $organizationObject->getId(), ] @@ -1254,7 +1254,7 @@ public function handleOrganizationDeletion(object $organizationObject): void { $this->deactivateUsersForOrganization(organizationUuid: $organizationUuid); $this->_logger->info( - 'SoftwareCatalogueService: Successfully handled organization deletion', + 'StackiqService: Successfully handled organization deletion', [ 'organizationId' => $organizationUuid, 'timestamp' => date('Y-m-d H:i:s'), @@ -1262,7 +1262,7 @@ public function handleOrganizationDeletion(object $organizationObject): void { ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to handle organization deletion: ' . $e->getMessage(), + 'StackiqService: Failed to handle organization deletion: ' . $e->getMessage(), [ 'objectId' => $organizationObject->getId(), 'exception' => $e->getMessage(), @@ -1285,7 +1285,7 @@ public function handleOrganizationDeletion(object $organizationObject): void { public function syncOrganizationWithOpenRegister(object $organizationObject): bool { try { $this->_logger->info( - 'SoftwareCatalogueService: SYNC_STEP_1 - Starting syncOrganizationWithOpenRegister', + 'StackiqService: SYNC_STEP_1 - Starting syncOrganizationWithOpenRegister', [ 'objectId' => $organizationObject->getId(), 'objectClass' => get_class($organizationObject), @@ -1296,7 +1296,7 @@ public function syncOrganizationWithOpenRegister(object $organizationObject): bo $organizationUuid = $objectData['id'] ?? $organizationObject->getId(); $this->_logger->info( - 'SoftwareCatalogueService: SYNC_STEP_2 - Extracted organization data', + 'StackiqService: SYNC_STEP_2 - Extracted organization data', [ 'organizationUuid' => $organizationUuid, 'objectDataKeys' => array_keys($objectData), @@ -1305,24 +1305,24 @@ public function syncOrganizationWithOpenRegister(object $organizationObject): bo ); // Get OpenRegister OrganisationService for proper organization entity management. - $this->_logger->info('SoftwareCatalogueService: SYNC_STEP_3 - Getting OrganisationService'); + $this->_logger->info('StackiqService: SYNC_STEP_3 - Getting OrganisationService'); $organisationService = $this->getOrganisationService(); if ($organisationService === null) { $this->_logger->error( - 'SoftwareCatalogueService: SYNC_STEP_3 - OpenRegister OrganisationService not available' + 'StackiqService: SYNC_STEP_3 - OpenRegister OrganisationService not available' ); return false; } $this->_logger->info( - 'SoftwareCatalogueService: SYNC_STEP_3 - OrganisationService retrieved', + 'StackiqService: SYNC_STEP_3 - OrganisationService retrieved', [ 'serviceClass' => get_class($organisationService), ] ); $this->_logger->info( - 'SoftwareCatalogueService: SYNC_STEP_4 - OpenRegister configuration', + 'StackiqService: SYNC_STEP_4 - OpenRegister configuration', [ 'organizationUuid' => $organizationUuid, 'organizationName' => $objectData['name'] ?? 'Unknown', @@ -1330,19 +1330,19 @@ public function syncOrganizationWithOpenRegister(object $organizationObject): bo ); // Check if organization already exists in OpenRegister. - $this->_logger->info('SoftwareCatalogueService: SYNC_STEP_5 - Checking if organization exists in OpenRegister'); + $this->_logger->info('StackiqService: SYNC_STEP_5 - Checking if organization exists in OpenRegister'); try { - $this->_logger->info('SoftwareCatalogueService: SYNC_STEP_5A - Getting OrganisationMapper for lookup'); + $this->_logger->info('StackiqService: SYNC_STEP_5A - Getting OrganisationMapper for lookup'); $organisationMapper = $this->getOrganisationMapper(); if ($organisationMapper === null) { $this->_logger->error( - 'SoftwareCatalogueService: OpenRegister OrganisationMapper not available, cannot sync organization' + 'StackiqService: OpenRegister OrganisationMapper not available, cannot sync organization' ); return false; } $this->_logger->info( - 'SoftwareCatalogueService: SYNC_STEP_5B - Calling findByUuid', + 'StackiqService: SYNC_STEP_5B - Calling findByUuid', [ 'uuid' => $organizationUuid, ] @@ -1351,15 +1351,15 @@ public function syncOrganizationWithOpenRegister(object $organizationObject): bo // Organization exists - update it. $this->_logger->info( - 'SoftwareCatalogueService: SYNC_STEP_6 - Organization exists in OpenRegister, updating', + 'StackiqService: SYNC_STEP_6 - Organization exists in OpenRegister, updating', [ 'organizationId' => $organizationUuid, 'existingOrganisationClass' => get_class($existingOrganisation), ] ); - // Map status from SoftwareCatalog to OpenRegister. - $this->_logger->info('SoftwareCatalogueService: SYNC_STEP_7 - Mapping organization data'); + // Map status from Stackiq to OpenRegister. + $this->_logger->info('StackiqService: SYNC_STEP_7 - Mapping organization data'); $mappedData = $this->mapOrganizationDataForOpenRegister(objectData: $objectData); // Update the organization using OrganisationService. @@ -1370,7 +1370,7 @@ public function syncOrganizationWithOpenRegister(object $organizationObject): bo ); $this->_logger->info( - 'SoftwareCatalogueService: Successfully updated organization in OpenRegister', + 'StackiqService: Successfully updated organization in OpenRegister', [ 'organizationId' => $organizationUuid, 'openRegisterId' => $updatedOrganisation->getUuid(), @@ -1381,19 +1381,19 @@ public function syncOrganizationWithOpenRegister(object $organizationObject): bo } catch (\OCP\AppFramework\Db\DoesNotExistException $e) { // Organization doesn't exist - create it. $this->_logger->info( - 'SoftwareCatalogueService: SYNC_STEP_8 - Organization not found in OpenRegister, creating', + 'StackiqService: SYNC_STEP_8 - Organization not found in OpenRegister, creating', [ 'organizationId' => $organizationUuid, 'exception' => $e->getMessage(), ] ); - // Map status from SoftwareCatalog to OpenRegister. - $this->_logger->info('SoftwareCatalogueService: SYNC_STEP_9 - Mapping organization data for creation'); + // Map status from Stackiq to OpenRegister. + $this->_logger->info('StackiqService: SYNC_STEP_9 - Mapping organization data for creation'); $mappedData = $this->mapOrganizationDataForOpenRegister(objectData: $objectData); // Create the organization using OrganisationService. - $this->_logger->info('SoftwareCatalogueService: SYNC_STEP_10 - Calling createOrganisationInOpenRegister'); + $this->_logger->info('StackiqService: SYNC_STEP_10 - Calling createOrganisationInOpenRegister'); $createdOrganisation = $this->createOrganisationInOpenRegisterInternal( organisationService: $organisationService, mappedData: $mappedData, @@ -1401,7 +1401,7 @@ public function syncOrganizationWithOpenRegister(object $organizationObject): bo ); $this->_logger->info( - 'SoftwareCatalogueService: SYNC_STEP_11 - Successfully created organization in OpenRegister', + 'StackiqService: SYNC_STEP_11 - Successfully created organization in OpenRegister', [ 'organizationId' => $organizationUuid, 'openRegisterId' => $createdOrganisation->getUuid(), @@ -1413,7 +1413,7 @@ public function syncOrganizationWithOpenRegister(object $organizationObject): bo }//end try } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to sync organization with OpenRegister: ' . $e->getMessage(), + 'StackiqService: Failed to sync organization with OpenRegister: ' . $e->getMessage(), [ 'objectId' => $organizationObject->getId(), 'exception' => $e->getMessage(), @@ -1438,7 +1438,7 @@ public function createOrganisationInOpenRegister(array $objectData): ?object { try { $organizationUuid = $objectData['id'] ?? null; if ($organizationUuid === null) { - $this->_logger->error('SoftwareCatalogueService: No organization UUID provided for creation'); + $this->_logger->error('StackiqService: No organization UUID provided for creation'); return null; } @@ -1462,7 +1462,7 @@ public function createOrganisationInOpenRegister(array $objectData): ?object { ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Error in public createOrganisationInOpenRegister', + 'StackiqService: Error in public createOrganisationInOpenRegister', [ 'error' => $e->getMessage(), 'objectData' => $objectData, @@ -1506,7 +1506,7 @@ private function createOrganisationInOpenRegisterInternal( string $organizationUuid, ): \OCA\OpenRegister\Db\Organisation { $this->_logger->info( - 'SoftwareCatalogueService: STEP 1 - Starting createOrganisationInOpenRegister', + 'StackiqService: STEP 1 - Starting createOrganisationInOpenRegister', [ 'organizationUuid' => $organizationUuid, 'name' => $mappedData['name'] ?? 'Unknown', @@ -1524,7 +1524,7 @@ private function createOrganisationInOpenRegisterInternal( } $this->_logger->info( - 'SoftwareCatalogueService: STEP 2 - Checking user context', + 'StackiqService: STEP 2 - Checking user context', [ // Always true: $userSession is an injected, non-nullable IUserSession. 'hasUserSession' => true, @@ -1535,7 +1535,7 @@ private function createOrganisationInOpenRegisterInternal( if ($currentUser === null) { $this->_logger->info( - 'SoftwareCatalogueService: STEP 3A - Anonymous path: No user, creating org directly via mapper', + 'StackiqService: STEP 3A - Anonymous path: No user, creating org directly via mapper', [ 'organizationUuid' => $organizationUuid, ] @@ -1543,14 +1543,14 @@ private function createOrganisationInOpenRegisterInternal( // Keep the original UUID format - no conversion needed. $this->_logger->info( - 'SoftwareCatalogueService: STEP 3B - Using original UUID format for OpenRegister (anonymous)', + 'StackiqService: STEP 3B - Using original UUID format for OpenRegister (anonymous)', [ 'organizationUuid' => $organizationUuid, ] ); // Create organization directly via mapper to avoid user context requirements. - $this->_logger->info('SoftwareCatalogueService: STEP 3C - Getting OrganisationMapper from container'); + $this->_logger->info('StackiqService: STEP 3C - Getting OrganisationMapper from container'); $organisationMapper = $this->getOrganisationMapper(); if ($organisationMapper === null) { // This method's return type is non-nullable and its caller already @@ -1560,18 +1560,18 @@ private function createOrganisationInOpenRegisterInternal( } $this->_logger->info( - 'SoftwareCatalogueService: STEP 3D - OrganisationMapper retrieved', + 'StackiqService: STEP 3D - OrganisationMapper retrieved', [ 'mapperClass' => get_class($organisationMapper), ] ); // Create a new Organisation entity. - $this->_logger->info('SoftwareCatalogueService: STEP 3E - Creating new Organisation entity'); + $this->_logger->info('StackiqService: STEP 3E - Creating new Organisation entity'); $organisation = new \OCA\OpenRegister\Db\Organisation(); $this->_logger->info( - 'SoftwareCatalogueService: STEP 3F - Setting organisation properties', + 'StackiqService: STEP 3F - Setting organisation properties', [ 'name' => $mappedData['name'] ?? 'Unknown Organization', 'description' => $mappedData['website'] ?? '', @@ -1590,7 +1590,7 @@ private function createOrganisationInOpenRegisterInternal( $allUsernames = array_unique($allUsernames); $this->_logger->info( - 'SoftwareCatalogueService: STEP 3F_2 - Collected usernames for organization', + 'StackiqService: STEP 3F_2 - Collected usernames for organization', [ 'organizationUuid' => $organizationUuid, 'totalUsernames' => count($allUsernames), @@ -1609,7 +1609,7 @@ private function createOrganisationInOpenRegisterInternal( // Set active status based on organization beoordeling. // Debug: Check if UUID was set correctly. $this->_logger->info( - 'SoftwareCatalogueService: STEP 3G - Debug - UUID before save', + 'StackiqService: STEP 3G - Debug - UUID before save', [ 'setUuid' => $organizationUuid, 'getUuid' => $organisation->getUuid(), @@ -1619,15 +1619,15 @@ private function createOrganisationInOpenRegisterInternal( ); // Save the organization. - $this->_logger->info('SoftwareCatalogueService: STEP 3H - Calling organisationMapper->save()'); + $this->_logger->info('StackiqService: STEP 3H - Calling organisationMapper->save()'); try { $savedOrganisation = $organisationMapper->save($organisation); $this->_logger->info( - 'SoftwareCatalogueService: STEP 3I - organisationMapper->save() completed' + 'StackiqService: STEP 3I - organisationMapper->save() completed' ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: STEP 3I - organisationMapper->save() failed', + 'StackiqService: STEP 3I - organisationMapper->save() failed', [ 'error' => $e->getMessage(), 'errorClass' => get_class($e), @@ -1638,7 +1638,7 @@ private function createOrganisationInOpenRegisterInternal( } $this->_logger->info( - 'SoftwareCatalogueService: Successfully created organization in OpenRegister via mapper', + 'StackiqService: Successfully created organization in OpenRegister via mapper', [ 'organizationUuid' => $organizationUuid, 'openRegisterId' => $savedOrganisation->getUuid(), @@ -1650,7 +1650,7 @@ private function createOrganisationInOpenRegisterInternal( // Verify the UUID was preserved. if ($savedOrganisation->getUuid() !== $organizationUuid) { $this->_logger->warning( - 'SoftwareCatalogueService: UUID mismatch after saving organization', + 'StackiqService: UUID mismatch after saving organization', [ 'expectedUuid' => $organizationUuid, 'actualUuid' => $savedOrganisation->getUuid(), @@ -1660,7 +1660,7 @@ private function createOrganisationInOpenRegisterInternal( }//end if $this->_logger->info( - 'SoftwareCatalogueService: STEP 4A - Auth path: User logged in, creating org via mapper', + 'StackiqService: STEP 4A - Auth path: User logged in, creating org via mapper', [ 'organizationUuid' => $organizationUuid, 'currentUser' => $currentUser->getUID(), @@ -1669,14 +1669,14 @@ private function createOrganisationInOpenRegisterInternal( // Keep the original UUID format - no conversion needed. $this->_logger->info( - 'SoftwareCatalogueService: STEP 4B - Using original UUID format for OpenRegister', + 'StackiqService: STEP 4B - Using original UUID format for OpenRegister', [ 'organizationUuid' => $organizationUuid, ] ); // Create organization directly via mapper to avoid service issues. - $this->_logger->info('SoftwareCatalogueService: STEP 4C - Getting OrganisationMapper from container'); + $this->_logger->info('StackiqService: STEP 4C - Getting OrganisationMapper from container'); $organisationMapper = $this->getOrganisationMapper(); if ($organisationMapper === null) { // Non-nullable return type, same reasoning as the anonymous branch above. @@ -1684,7 +1684,7 @@ private function createOrganisationInOpenRegisterInternal( } $this->_logger->info( - 'SoftwareCatalogueService: STEP 4D - OrganisationMapper retrieved', + 'StackiqService: STEP 4D - OrganisationMapper retrieved', [ 'mapperClass' => get_class($organisationMapper), ] @@ -1702,7 +1702,7 @@ private function createOrganisationInOpenRegisterInternal( $allUsernames = array_unique($allUsernames); $this->_logger->info( - 'SoftwareCatalogueService: STEP 4E - Debug - UUID before createWithUuid', + 'StackiqService: STEP 4E - Debug - UUID before createWithUuid', [ 'organizationUuid' => $organizationUuid, 'uuidLength' => strlen($organizationUuid), @@ -1715,11 +1715,11 @@ private function createOrganisationInOpenRegisterInternal( ] ); - $this->_logger->info('SoftwareCatalogueService: STEP 4F - Calling organisationMapper->createWithUuid()'); + $this->_logger->info('StackiqService: STEP 4F - Calling organisationMapper->createWithUuid()'); try { // Debug: Log the exact parameters being passed. $this->_logger->info( - 'SoftwareCatalogueService: STEP 4F_DEBUG - Parameters for createWithUuid', + 'StackiqService: STEP 4F_DEBUG - Parameters for createWithUuid', [ 'name' => $mappedData['name'] ?? 'Unknown Organization', 'description' => $mappedData['website'] ?? '', @@ -1746,11 +1746,11 @@ private function createOrganisationInOpenRegisterInternal( // Not default. ); $this->_logger->info( - 'SoftwareCatalogueService: STEP 4G - organisationMapper->createWithUuid() completed' + 'StackiqService: STEP 4G - organisationMapper->createWithUuid() completed' ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: STEP 4G - organisationMapper->createWithUuid() failed', + 'StackiqService: STEP 4G - organisationMapper->createWithUuid() failed', [ 'error' => $e->getMessage(), 'errorClass' => get_class($e), @@ -1761,9 +1761,9 @@ private function createOrganisationInOpenRegisterInternal( }//end try // Note: OpenRegister Organisation entity doesn't have status or type fields. - // These are managed in the SoftwareCatalog object, not in the OpenRegister organisation. + // These are managed in the Stackiq object, not in the OpenRegister organisation. $this->_logger->info( - 'SoftwareCatalogueService: Successfully created organization in OpenRegister via service', + 'StackiqService: Successfully created organization in OpenRegister via service', [ 'organizationUuid' => $organizationUuid, 'openRegisterId' => $organisation->getUuid(), @@ -1790,7 +1790,7 @@ private function updateOrganisationInOpenRegister( array $mappedData, ): \OCA\OpenRegister\Db\Organisation { $this->_logger->info( - 'SoftwareCatalogueService: Updating organization in OpenRegister', + 'StackiqService: Updating organization in OpenRegister', [ 'organizationUuid' => $existingOrganisation->getUuid(), 'name' => $mappedData['name'] ?? 'Unknown', @@ -1807,7 +1807,7 @@ private function updateOrganisationInOpenRegister( } // Note: OpenRegister Organisation entity doesn't have status or type fields. - // These are managed in the SoftwareCatalog object, not in the OpenRegister organisation. + // These are managed in the Stackiq object, not in the OpenRegister organisation. // Save the updated organization. $organisationMapper = $this->getOrganisationMapper(); if ($organisationMapper === null) { @@ -1819,7 +1819,7 @@ private function updateOrganisationInOpenRegister( $updatedOrganisation = $organisationMapper->save($existingOrganisation); $this->_logger->info( - 'SoftwareCatalogueService: Successfully updated organization in OpenRegister', + 'StackiqService: Successfully updated organization in OpenRegister', [ 'organizationUuid' => $existingOrganisation->getUuid(), 'openRegisterId' => $updatedOrganisation->getUuid(), @@ -1844,7 +1844,7 @@ private function collectContactPersonUsernames(string $organizationUuid, array $ // These are available immediately when the organization is created. $nestedContactPersons = $objectData['contactpersonen'] ?? []; $this->_logger->info( - 'SoftwareCatalogueService: Processing nested contact persons', + 'StackiqService: Processing nested contact persons', [ 'organizationUuid' => $organizationUuid, 'nestedContactPersonCount' => count($nestedContactPersons), @@ -1855,7 +1855,7 @@ private function collectContactPersonUsernames(string $organizationUuid, array $ if (is_array($contactPerson) === true && isset($contactPerson['email']) === true) { $usernames[] = $contactPerson['email']; $this->_logger->info( - 'SoftwareCatalogueService: Added nested contact person username', + 'StackiqService: Added nested contact person username', [ 'username' => $contactPerson['email'], 'contactPersonData' => $contactPerson, @@ -1868,13 +1868,13 @@ private function collectContactPersonUsernames(string $organizationUuid, array $ // This is useful for updates or when contact persons were created separately. $objectService = $this->getObjectService(); if (empty($objectService) === false) { - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $voorzieningenConfig = $settingsService->getVoorzieningenConfig(); $contactSchemaId = $voorzieningenConfig['contactpersoon_schema'] ?? null; if ($contactSchemaId === null) { $this->_logger->warning( - 'SoftwareCatalogueService: Missing contactpersoon schema config for username extraction' + 'StackiqService: Missing contactpersoon schema config for username extraction' ); return $usernames; } @@ -1896,7 +1896,7 @@ private function collectContactPersonUsernames(string $organizationUuid, array $ ); } catch (\Exception $e) { $this->_logger->info( - 'SoftwareCatalogueService: Approach 1 failed, trying approach 2', + 'StackiqService: Approach 1 failed, trying approach 2', [ 'organizationUuid' => $organizationUuid, 'error' => $e->getMessage(), @@ -1925,7 +1925,7 @@ private function collectContactPersonUsernames(string $organizationUuid, array $ } } catch (\Exception $e) { $this->_logger->info( - 'SoftwareCatalogueService: Approach 2 also failed', + 'StackiqService: Approach 2 also failed', [ 'organizationUuid' => $organizationUuid, 'error' => $e->getMessage(), @@ -1935,7 +1935,7 @@ private function collectContactPersonUsernames(string $organizationUuid, array $ }//end if $this->_logger->info( - 'SoftwareCatalogueService: Found existing contact persons for organization', + 'StackiqService: Found existing contact persons for organization', [ 'organizationUuid' => $organizationUuid, 'contactPersonCount' => count($contactPersons), @@ -1954,7 +1954,7 @@ function ($cp) { if (empty($email) === false) { $usernames[] = $email; $this->_logger->info( - 'SoftwareCatalogueService: Added existing contact person username', + 'StackiqService: Added existing contact person username', [ 'username' => $email, 'contactPersonId' => $contactPerson->getId(), @@ -1964,7 +1964,7 @@ function ($cp) { } } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Error collecting existing contact person usernames', + 'StackiqService: Error collecting existing contact person usernames', [ 'organizationUuid' => $organizationUuid, 'error' => $e->getMessage(), @@ -1976,7 +1976,7 @@ function ($cp) { // Remove duplicates and return. $uniqueUsernames = array_unique($usernames); $this->_logger->info( - 'SoftwareCatalogueService: Collected contact person usernames', + 'StackiqService: Collected contact person usernames', [ 'organizationUuid' => $organizationUuid, 'totalUsernames' => count($uniqueUsernames), @@ -1988,9 +1988,9 @@ function ($cp) { }//end collectContactPersonUsernames() /** - * Maps organization data from SoftwareCatalog format to OpenRegister format + * Maps organization data from Stackiq format to OpenRegister format * - * @param array $objectData The organization data from SoftwareCatalog + * @param array $objectData The organization data from Stackiq * * @return array The mapped data for OpenRegister */ @@ -2005,7 +2005,7 @@ private function mapOrganizationDataForOpenRegister(array $objectData): array { 'participants' => [], ]; - // Map status from SoftwareCatalog to OpenRegister. + // Map status from Stackiq to OpenRegister. $assessment = strtolower($objectData['beoordeling'] ?? ''); if ($assessment === 'actief') { $mappedData['active'] = true; @@ -2047,7 +2047,7 @@ private function mapOrganizationDataForOpenRegister(array $objectData): array { private function activateUsersForOrganization(string $organizationUuid): void { try { $this->_logger->info( - 'SoftwareCatalogueService: Activating users for organization', + 'StackiqService: Activating users for organization', [ 'organizationUuid' => $organizationUuid, ] @@ -2055,7 +2055,7 @@ private function activateUsersForOrganization(string $organizationUuid): void { $objectService = $this->getObjectService(); if ($objectService === null) { - $this->_logger->error('SoftwareCatalogueService: OpenRegister ObjectService not available'); + $this->_logger->error('StackiqService: OpenRegister ObjectService not available'); return; } @@ -2097,7 +2097,7 @@ private function activateUsersForOrganization(string $organizationUuid): void { $activatedCount++; $this->_logger->info( - 'SoftwareCatalogueService: Activated user for organization', + 'StackiqService: Activated user for organization', [ 'username' => $username, 'organizationUuid' => $organizationUuid, @@ -2108,7 +2108,7 @@ private function activateUsersForOrganization(string $organizationUuid): void { } $this->_logger->info( - 'SoftwareCatalogueService: Completed user activation for organization', + 'StackiqService: Completed user activation for organization', [ 'organizationUuid' => $organizationUuid, 'totalContactpersonen' => count($contactpersonen), @@ -2117,7 +2117,7 @@ private function activateUsersForOrganization(string $organizationUuid): void { ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to activate users for organization: ' . $e->getMessage(), + 'StackiqService: Failed to activate users for organization: ' . $e->getMessage(), [ 'organizationUuid' => $organizationUuid, 'exception' => $e->getMessage(), @@ -2139,7 +2139,7 @@ private function activateUsersForOrganization(string $organizationUuid): void { private function deactivateUsersForOrganization(string $organizationUuid): void { try { $this->_logger->info( - 'SoftwareCatalogueService: Deactivating users for organization', + 'StackiqService: Deactivating users for organization', [ 'organizationUuid' => $organizationUuid, ] @@ -2147,7 +2147,7 @@ private function deactivateUsersForOrganization(string $organizationUuid): void $objectService = $this->getObjectService(); if ($objectService === null) { - $this->_logger->error('SoftwareCatalogueService: OpenRegister ObjectService not available'); + $this->_logger->error('StackiqService: OpenRegister ObjectService not available'); return; } @@ -2189,7 +2189,7 @@ private function deactivateUsersForOrganization(string $organizationUuid): void $deactivatedCount++; $this->_logger->info( - 'SoftwareCatalogueService: Deactivated user for organization', + 'StackiqService: Deactivated user for organization', [ 'username' => $username, 'organizationUuid' => $organizationUuid, @@ -2200,7 +2200,7 @@ private function deactivateUsersForOrganization(string $organizationUuid): void } $this->_logger->info( - 'SoftwareCatalogueService: Completed user deactivation for organization', + 'StackiqService: Completed user deactivation for organization', [ 'organizationUuid' => $organizationUuid, 'totalContactpersonen' => count($contactpersonen), @@ -2209,7 +2209,7 @@ private function deactivateUsersForOrganization(string $organizationUuid): void ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to deactivate users for organization: ' . $e->getMessage(), + 'StackiqService: Failed to deactivate users for organization: ' . $e->getMessage(), [ 'organizationUuid' => $organizationUuid, 'exception' => $e->getMessage(), @@ -2222,28 +2222,28 @@ private function deactivateUsersForOrganization(string $organizationUuid): void }//end deactivateUsersForOrganization() /** - * Activates SoftwareCatalog-specific users for an organization + * Activates Stackiq-specific users for an organization * Only affects users from contactpersoon objects, not admin group users * * @param string $organizationUuid The organization UUID * * @return void */ - private function activateSoftwareCatalogUsersForOrganization(string $organizationUuid): void { + private function activateStackiqUsersForOrganization(string $organizationUuid): void { try { $this->_logger->info( - 'SoftwareCatalogueService: Activating SoftwareCatalog users for organization', + 'StackiqService: Activating Stackiq users for organization', [ 'organizationUuid' => $organizationUuid, ] ); - // Get SoftwareCatalog-specific users (from contactpersonen). - $softwareCatalogUsers = $this->getSoftwareCatalogUsersForOrganization(organizationUuid: $organizationUuid); + // Get Stackiq-specific users (from contactpersonen). + $softwareCatalogUsers = $this->getStackiqUsersForOrganization(organizationUuid: $organizationUuid); if (empty($softwareCatalogUsers) === true) { $this->_logger->info( - 'SoftwareCatalogueService: No SoftwareCatalog users found for organization', + 'StackiqService: No Stackiq users found for organization', [ 'organizationUuid' => $organizationUuid, ] @@ -2252,7 +2252,7 @@ private function activateSoftwareCatalogUsersForOrganization(string $organizatio } $this->_logger->info( - 'SoftwareCatalogueService: Found SoftwareCatalog users to activate', + 'StackiqService: Found Stackiq users to activate', [ 'organizationUuid' => $organizationUuid, 'userCount' => count($softwareCatalogUsers), @@ -2272,7 +2272,7 @@ private function activateSoftwareCatalogUsersForOrganization(string $organizatio $user->setEnabled(true); $activatedUsers[] = $username; $this->_logger->debug( - 'SoftwareCatalogueService: Activated SoftwareCatalog user', + 'StackiqService: Activated Stackiq user', [ 'organizationUuid' => $organizationUuid, 'username' => $username, @@ -2280,7 +2280,7 @@ private function activateSoftwareCatalogUsersForOrganization(string $organizatio ); } elseif ($user !== false && $user->isEnabled() === true) { $this->_logger->debug( - 'SoftwareCatalogueService: SoftwareCatalog user already active', + 'StackiqService: Stackiq user already active', [ 'organizationUuid' => $organizationUuid, 'username' => $username, @@ -2289,7 +2289,7 @@ private function activateSoftwareCatalogUsersForOrganization(string $organizatio } else { $failedUsers[] = $username; $this->_logger->warning( - 'SoftwareCatalogueService: SoftwareCatalog user not found', + 'StackiqService: Stackiq user not found', [ 'organizationUuid' => $organizationUuid, 'username' => $username, @@ -2299,7 +2299,7 @@ private function activateSoftwareCatalogUsersForOrganization(string $organizatio } catch (\Exception $e) { $failedUsers[] = $username; $this->_logger->error( - 'SoftwareCatalogueService: Failed to activate SoftwareCatalog user', + 'StackiqService: Failed to activate Stackiq user', [ 'organizationUuid' => $organizationUuid, 'username' => $username, @@ -2310,7 +2310,7 @@ private function activateSoftwareCatalogUsersForOrganization(string $organizatio }//end foreach $this->_logger->info( - 'SoftwareCatalogueService: SoftwareCatalog user activation complete', + 'StackiqService: Stackiq user activation complete', [ 'organizationUuid' => $organizationUuid, 'activatedUsers' => $activatedUsers, @@ -2320,38 +2320,38 @@ private function activateSoftwareCatalogUsersForOrganization(string $organizatio ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Error activating SoftwareCatalog users for organization', + 'StackiqService: Error activating Stackiq users for organization', [ 'organizationUuid' => $organizationUuid, 'error' => $e->getMessage(), ] ); }//end try - }//end activateSoftwareCatalogUsersForOrganization() + }//end activateStackiqUsersForOrganization() /** - * Deactivates SoftwareCatalog-specific users for an organization + * Deactivates Stackiq-specific users for an organization * Only affects users from contactpersoon objects, not admin group users * * @param string $organizationUuid The organization UUID * * @return void */ - private function deactivateSoftwareCatalogUsersForOrganization(string $organizationUuid): void { + private function deactivateStackiqUsersForOrganization(string $organizationUuid): void { try { $this->_logger->info( - 'SoftwareCatalogueService: Deactivating SoftwareCatalog users for organization', + 'StackiqService: Deactivating Stackiq users for organization', [ 'organizationUuid' => $organizationUuid, ] ); - // Get SoftwareCatalog-specific users (from contactpersonen). - $softwareCatalogUsers = $this->getSoftwareCatalogUsersForOrganization(organizationUuid: $organizationUuid); + // Get Stackiq-specific users (from contactpersonen). + $softwareCatalogUsers = $this->getStackiqUsersForOrganization(organizationUuid: $organizationUuid); if (empty($softwareCatalogUsers) === true) { $this->_logger->info( - 'SoftwareCatalogueService: No SoftwareCatalog users found for organization', + 'StackiqService: No Stackiq users found for organization', [ 'organizationUuid' => $organizationUuid, ] @@ -2360,7 +2360,7 @@ private function deactivateSoftwareCatalogUsersForOrganization(string $organizat } $this->_logger->info( - 'SoftwareCatalogueService: Found SoftwareCatalog users to deactivate', + 'StackiqService: Found Stackiq users to deactivate', [ 'organizationUuid' => $organizationUuid, 'userCount' => count($softwareCatalogUsers), @@ -2380,7 +2380,7 @@ private function deactivateSoftwareCatalogUsersForOrganization(string $organizat $user->setEnabled(false); $deactivatedUsers[] = $username; $this->_logger->debug( - 'SoftwareCatalogueService: Deactivated SoftwareCatalog user', + 'StackiqService: Deactivated Stackiq user', [ 'organizationUuid' => $organizationUuid, 'username' => $username, @@ -2388,7 +2388,7 @@ private function deactivateSoftwareCatalogUsersForOrganization(string $organizat ); } elseif ($user !== false && $user->isEnabled() === false) { $this->_logger->debug( - 'SoftwareCatalogueService: SoftwareCatalog user already inactive', + 'StackiqService: Stackiq user already inactive', [ 'organizationUuid' => $organizationUuid, 'username' => $username, @@ -2397,7 +2397,7 @@ private function deactivateSoftwareCatalogUsersForOrganization(string $organizat } else { $failedUsers[] = $username; $this->_logger->warning( - 'SoftwareCatalogueService: SoftwareCatalog user not found', + 'StackiqService: Stackiq user not found', [ 'organizationUuid' => $organizationUuid, 'username' => $username, @@ -2407,7 +2407,7 @@ private function deactivateSoftwareCatalogUsersForOrganization(string $organizat } catch (\Exception $e) { $failedUsers[] = $username; $this->_logger->error( - 'SoftwareCatalogueService: Failed to deactivate SoftwareCatalog user', + 'StackiqService: Failed to deactivate Stackiq user', [ 'organizationUuid' => $organizationUuid, 'username' => $username, @@ -2418,7 +2418,7 @@ private function deactivateSoftwareCatalogUsersForOrganization(string $organizat }//end foreach $this->_logger->info( - 'SoftwareCatalogueService: SoftwareCatalog user deactivation complete', + 'StackiqService: Stackiq user deactivation complete', [ 'organizationUuid' => $organizationUuid, 'deactivatedUsers' => $deactivatedUsers, @@ -2428,27 +2428,27 @@ private function deactivateSoftwareCatalogUsersForOrganization(string $organizat ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Error deactivating SoftwareCatalog users for organization', + 'StackiqService: Error deactivating Stackiq users for organization', [ 'organizationUuid' => $organizationUuid, 'error' => $e->getMessage(), ] ); }//end try - }//end deactivateSoftwareCatalogUsersForOrganization() + }//end deactivateStackiqUsersForOrganization() /** - * Gets SoftwareCatalog-specific users for an organization + * Gets Stackiq-specific users for an organization * These are users from contactpersoon objects, excluding admin group users * * @param string $organizationUuid The organization UUID * * @return array Array of usernames */ - private function getSoftwareCatalogUsersForOrganization(string $organizationUuid): array { + private function getStackiqUsersForOrganization(string $organizationUuid): array { try { $this->_logger->debug( - 'SoftwareCatalogueService: Getting SoftwareCatalog users for organization', + 'StackiqService: Getting Stackiq users for organization', [ 'organizationUuid' => $organizationUuid, ] @@ -2458,7 +2458,7 @@ private function getSoftwareCatalogUsersForOrganization(string $organizationUuid $objectService = $this->getObjectService(); if ($objectService === null) { $this->_logger->error( - 'SoftwareCatalogueService: ObjectService not available for getting SoftwareCatalog users' + 'StackiqService: ObjectService not available for getting Stackiq users' ); return []; } @@ -2491,7 +2491,7 @@ private function getSoftwareCatalogUsersForOrganization(string $organizationUuid if ($username !== false && in_array($username, $adminGroupUsers) === false) { $softwareCatalogUsers[] = $username; $this->_logger->debug( - 'SoftwareCatalogueService: Found SoftwareCatalog user', + 'StackiqService: Found Stackiq user', [ 'organizationUuid' => $organizationUuid, 'username' => $username, @@ -2503,7 +2503,7 @@ private function getSoftwareCatalogUsersForOrganization(string $organizationUuid }//end foreach $this->_logger->info( - 'SoftwareCatalogueService: Found SoftwareCatalog users for organization', + 'StackiqService: Found Stackiq users for organization', [ 'organizationUuid' => $organizationUuid, 'userCount' => count($softwareCatalogUsers), @@ -2514,7 +2514,7 @@ private function getSoftwareCatalogUsersForOrganization(string $organizationUuid return $softwareCatalogUsers; } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Error getting SoftwareCatalog users for organization', + 'StackiqService: Error getting Stackiq users for organization', [ 'organizationUuid' => $organizationUuid, 'error' => $e->getMessage(), @@ -2522,7 +2522,7 @@ private function getSoftwareCatalogUsersForOrganization(string $organizationUuid ); return []; }//end try - }//end getSoftwareCatalogUsersForOrganization() + }//end getStackiqUsersForOrganization() /** * Gets all usernames from the admin group @@ -2535,7 +2535,7 @@ private function getAdminGroupUsernames(): array { $adminGroup = $groupManager->get('admin'); if ($adminGroup === null) { - $this->_logger->warning('SoftwareCatalogueService: Admin group not found'); + $this->_logger->warning('StackiqService: Admin group not found'); return []; } @@ -2547,7 +2547,7 @@ private function getAdminGroupUsernames(): array { } $this->_logger->debug( - 'SoftwareCatalogueService: Found admin group users', + 'StackiqService: Found admin group users', [ 'adminUserCount' => count($adminUsernames), 'adminUsers' => $adminUsernames, @@ -2557,7 +2557,7 @@ private function getAdminGroupUsernames(): array { return $adminUsernames; } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Error getting admin group usernames', + 'StackiqService: Error getting admin group usernames', [ 'error' => $e->getMessage(), ] @@ -2576,7 +2576,7 @@ private function getAdminGroupUsernames(): array { private function addAdminGroupUsersToOrganization(string $organizationUuid): void { try { $this->_logger->info( - 'SoftwareCatalogueService: Adding admin group users to organization entity', + 'StackiqService: Adding admin group users to organization entity', [ 'organizationUuid' => $organizationUuid, ] @@ -2587,13 +2587,13 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi $adminGroup = $groupManager->get('admin'); if ($adminGroup === null) { - $this->_logger->warning('SoftwareCatalogueService: Admin group not found'); + $this->_logger->warning('StackiqService: Admin group not found'); return; } $adminUsers = $adminGroup->getUsers(); $this->_logger->info( - 'SoftwareCatalogueService: Found admin group users', + 'StackiqService: Found admin group users', [ 'organizationUuid' => $organizationUuid, 'adminUserCount' => count($adminUsers), @@ -2603,13 +2603,13 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi // Get the organization entity (not object) to update its users list. $organisationMapper = $this->_container->get('OCA\\OpenRegister\\Db\\OrganisationMapper'); if ($organisationMapper === null) { - $this->_logger->error('SoftwareCatalogueService: OrganisationMapper not available for adding admin users'); + $this->_logger->error('StackiqService: OrganisationMapper not available for adding admin users'); return; } // Find the organization entity by UUID. $this->_logger->info( - 'SoftwareCatalogueService: Searching for organization entity', + 'StackiqService: Searching for organization entity', [ 'organizationUuid' => $organizationUuid, ] @@ -2619,7 +2619,7 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi $targetOrganisation = $organisationMapper->findByUuid($organizationUuid); $this->_logger->info( - 'SoftwareCatalogueService: Found target organization entity', + 'StackiqService: Found target organization entity', [ 'organizationUuid' => $organizationUuid, 'entityId' => $targetOrganisation->getId(), @@ -2627,7 +2627,7 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi ); } catch (\OCP\AppFramework\Db\DoesNotExistException $e) { $this->_logger->warning( - 'SoftwareCatalogueService: Organization entity not found for adding admin users', + 'StackiqService: Organization entity not found for adding admin users', [ 'organizationUuid' => $organizationUuid, ] @@ -2639,7 +2639,7 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi $currentUsers = $targetOrganisation->getUsers() ?? []; $this->_logger->info( - 'SoftwareCatalogueService: Current organization entity users', + 'StackiqService: Current organization entity users', [ 'organizationUuid' => $organizationUuid, 'currentUsers' => $currentUsers, @@ -2656,7 +2656,7 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi $updatedUsers[] = $adminUsername; $addedUsers[] = $adminUsername; $this->_logger->debug( - 'SoftwareCatalogueService: Added admin user to organization entity', + 'StackiqService: Added admin user to organization entity', [ 'organizationUuid' => $organizationUuid, 'adminUsername' => $adminUsername, @@ -2666,7 +2666,7 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi } $this->_logger->info( - 'SoftwareCatalogueService: Admin users processing complete', + 'StackiqService: Admin users processing complete', [ 'organizationUuid' => $organizationUuid, 'addedUsers' => $addedUsers, @@ -2677,7 +2677,7 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi // Update the organization entity with the new users list. if (count($updatedUsers) > count($currentUsers)) { $this->_logger->info( - 'SoftwareCatalogueService: Updating organization entity with new users', + 'StackiqService: Updating organization entity with new users', [ 'organizationUuid' => $organizationUuid, 'entityId' => $targetOrganisation->getId(), @@ -2689,7 +2689,7 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi $targetOrganisation->setUsers($updatedUsers); $this->_logger->info( - 'SoftwareCatalogueService: Saving updated organization entity', + 'StackiqService: Saving updated organization entity', [ 'organizationUuid' => $organizationUuid, 'entityId' => $targetOrganisation->getId(), @@ -2701,7 +2701,7 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi $savedOrganisation = $organisationMapper->save($targetOrganisation); $this->_logger->info( - 'SoftwareCatalogueService: Successfully added admin users to organization entity', + 'StackiqService: Successfully added admin users to organization entity', [ 'organizationUuid' => $organizationUuid, 'addedUsers' => count($updatedUsers) - count($currentUsers), @@ -2710,7 +2710,7 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi ); } else { $this->_logger->info( - 'SoftwareCatalogueService: All admin users already in organization entity', + 'StackiqService: All admin users already in organization entity', [ 'organizationUuid' => $organizationUuid, 'totalUsers' => count($updatedUsers), @@ -2719,7 +2719,7 @@ private function addAdminGroupUsersToOrganization(string $organizationUuid): voi }//end if } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to add admin users to organization entity: ' . $e->getMessage(), + 'StackiqService: Failed to add admin users to organization entity: ' . $e->getMessage(), [ 'organizationUuid' => $organizationUuid, 'exception' => $e, @@ -2769,7 +2769,7 @@ public function shouldAddContactpersoonToOrganization(object $contactPersonObjec if (is_array($organizationUsers) === true && in_array($username, $organizationUsers) === false) { $this->_logger->info( - 'SoftwareCatalogueService: Contactpersoon should be added to organization', + 'StackiqService: Contactpersoon should be added to organization', [ 'username' => $username, 'organizationUuid' => $organizationUuid, @@ -2783,7 +2783,7 @@ public function shouldAddContactpersoonToOrganization(object $contactPersonObjec } catch (\OCP\AppFramework\Db\DoesNotExistException $e) { // Organization doesn't exist, so we can't add the user. $this->_logger->warning( - 'SoftwareCatalogueService: Organization not found for contactpersoon', + 'StackiqService: Organization not found for contactpersoon', [ 'username' => $username, 'organizationUuid' => $organizationUuid, @@ -2793,7 +2793,7 @@ public function shouldAddContactpersoonToOrganization(object $contactPersonObjec }//end try } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to check contactpersoon addition to org: ' . $e->getMessage(), + 'StackiqService: Failed to check contactpersoon addition to org: ' . $e->getMessage(), [ 'objectId' => $contactPersonObject->getId(), 'exception' => $e->getMessage(), @@ -2819,7 +2819,7 @@ public function addContactpersoonToOrganization(object $contactPersonObject): bo if (empty($username) === true || empty($organizationUuid) === true) { $this->_logger->warning( - 'SoftwareCatalogueService: Cannot add contactpersoon to org - missing username or org', + 'StackiqService: Cannot add contactpersoon to org - missing username or org', [ 'username' => $username, 'organizationUuid' => $organizationUuid, @@ -2830,7 +2830,7 @@ public function addContactpersoonToOrganization(object $contactPersonObject): bo $objectService = $this->getObjectService(); if ($objectService === null) { - $this->_logger->error('SoftwareCatalogueService: OpenRegister ObjectService not available'); + $this->_logger->error('StackiqService: OpenRegister ObjectService not available'); return false; } @@ -2867,7 +2867,7 @@ public function addContactpersoonToOrganization(object $contactPersonObject): bo ); $this->_logger->info( - 'SoftwareCatalogueService: Successfully added contactpersoon to organization', + 'StackiqService: Successfully added contactpersoon to organization', [ 'username' => $username, 'organizationUuid' => $organizationUuid, @@ -2877,7 +2877,7 @@ public function addContactpersoonToOrganization(object $contactPersonObject): bo }//end if $this->_logger->debug( - 'SoftwareCatalogueService: Contactpersoon already in organization', + 'StackiqService: Contactpersoon already in organization', [ 'username' => $username, 'organizationUuid' => $organizationUuid, @@ -2887,7 +2887,7 @@ public function addContactpersoonToOrganization(object $contactPersonObject): bo // Already there, consider it successful. } catch (\OCP\AppFramework\Db\DoesNotExistException $e) { $this->_logger->error( - 'SoftwareCatalogueService: Organization not found for contactpersoon', + 'StackiqService: Organization not found for contactpersoon', [ 'username' => $username, 'organizationUuid' => $organizationUuid, @@ -2897,7 +2897,7 @@ public function addContactpersoonToOrganization(object $contactPersonObject): bo }//end try } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to add contact person to organization: ' . $e->getMessage(), + 'StackiqService: Failed to add contact person to organization: ' . $e->getMessage(), [ 'objectId' => $contactPersonObject->getId(), 'exception' => $e->getMessage(), @@ -2920,7 +2920,7 @@ public function addContactpersoonToOrganization(object $contactPersonObject): bo private function handleOwnershipAssignment(object $organizationObject): void { try { $this->_logger->info( - 'SoftwareCatalogueService: Handling ownership assignment for organization', + 'StackiqService: Handling ownership assignment for organization', [ 'objectId' => $organizationObject->getId(), ] @@ -2932,7 +2932,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { if (empty($contactpersonen) === true) { $this->_logger->info( - 'SoftwareCatalogueService: No contact persons found for ownership assignment', + 'StackiqService: No contact persons found for ownership assignment', [ 'organizationUuid' => $organizationUuid, ] @@ -2946,7 +2946,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { $objectService = $this->getObjectService(); if ($objectService === null) { $this->_logger->error( - 'SoftwareCatalogueService: OpenRegister ObjectService not available for ownership assignment' + 'StackiqService: OpenRegister ObjectService not available for ownership assignment' ); return; } @@ -2959,7 +2959,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { if ($registerId === null || $contactPersonSchemaId === null || $organisationSchemaId === false) { $this->_logger->error( - 'SoftwareCatalogueService: Register or schema not configured for contactpersoon/organisatie' + 'StackiqService: Register or schema not configured for contactpersoon/organisatie' ); return; } @@ -2983,7 +2983,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { if (empty($primaryUsername) === true) { if ($retry < $maxRetries - 1) { $this->_logger->info( - 'SoftwareCatalogueService: Primary contact no username, retry in ' . $retryDelay . 's', + 'StackiqService: Primary contact no username, retry in ' . $retryDelay . 's', [ 'contactUuid' => $primaryContactUuid, 'organizationUuid' => $organizationUuid, @@ -2995,7 +2995,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { } $this->_logger->warning( - 'SoftwareCatalogueService: Primary contact person still has no username after retries', + 'StackiqService: Primary contact person still has no username after retries', [ 'contactUuid' => $primaryContactUuid, 'organizationUuid' => $organizationUuid, @@ -3030,7 +3030,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { } } catch (\Exception $e) { $this->_logger->warning( - 'SoftwareCatalogueService: Failed to add contact person to organization entity', + 'StackiqService: Failed to add contact person to organization entity', [ 'contactUuid' => $contactUuid, 'error' => $e->getMessage(), @@ -3043,7 +3043,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { $organisationMapper->save($organisationEntity); $this->_logger->info( - 'SoftwareCatalogueService: Successfully added users to organization entity', + 'StackiqService: Successfully added users to organization entity', [ 'organizationUuid' => $organisationEntityUuid, 'userCount' => count($organisationEntity->getUserIds()), @@ -3051,7 +3051,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { ); } catch (\OCP\AppFramework\Db\DoesNotExistException $e) { $this->_logger->error( - 'SoftwareCatalogueService: Organization entity not found for adding users', + 'StackiqService: Organization entity not found for adding users', [ 'organizationUuid' => $organisationEntityUuid, ] @@ -3110,7 +3110,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { } } catch (\Exception $e) { $this->_logger->warning( - 'SoftwareCatalogueService: Failed to update contact person ownership', + 'StackiqService: Failed to update contact person ownership', [ 'contactUuid' => $contactUuid, 'error' => $e->getMessage(), @@ -3120,7 +3120,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { }//end for $this->_logger->info( - 'SoftwareCatalogueService: Successfully assigned ownership for organization', + 'StackiqService: Successfully assigned ownership for organization', [ 'organizationUuid' => $organizationUuid, 'primaryOwner' => $primaryUsername, @@ -3135,7 +3135,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { } catch (\OCP\AppFramework\Db\DoesNotExistException $e) { if ($retry < $maxRetries - 1) { $this->_logger->info( - 'SoftwareCatalogueService: Primary contact not found, retrying in ' . $retryDelay . ' seconds', + 'StackiqService: Primary contact not found, retrying in ' . $retryDelay . ' seconds', [ 'contactUuid' => $primaryContactUuid, 'organizationUuid' => $organizationUuid, @@ -3147,7 +3147,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { } $this->_logger->error( - 'SoftwareCatalogueService: Primary contact person not found after retries', + 'StackiqService: Primary contact person not found after retries', [ 'contactUuid' => $primaryContactUuid, 'organizationUuid' => $organizationUuid, @@ -3158,7 +3158,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { }//end for } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Error handling ownership assignment', + 'StackiqService: Error handling ownership assignment', [ 'objectId' => $organizationObject->getId(), 'error' => $e->getMessage(), @@ -3181,7 +3181,7 @@ private function handleOwnershipAssignment(object $organizationObject): void { */ public function syncContactPersonUsernamesWithOrganization(string $organizationUuid): void { $this->_logger->info( - 'SoftwareCatalogueService: Starting contact person username synchronization', + 'StackiqService: Starting contact person username synchronization', [ 'organizationUuid' => $organizationUuid, ] @@ -3190,19 +3190,19 @@ public function syncContactPersonUsernamesWithOrganization(string $organizationU // Get the ObjectService to find contact persons. $objectService = $this->getObjectService(); if ($objectService === null) { - $this->_logger->error('SoftwareCatalogueService: ObjectService not available for username synchronization'); + $this->_logger->error('StackiqService: ObjectService not available for username synchronization'); return; } // Get the contact person schema ID from configuration. - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $voorzieningenConfig = $settingsService->getVoorzieningenConfig(); $contactSchemaId = $voorzieningenConfig['contactpersoon_schema'] ?? null; $registerId = $voorzieningenConfig['register'] ?? null; if ($contactSchemaId === null || $registerId === false) { $this->_logger->warning( - 'SoftwareCatalogueService: Missing Voorzieningen configuration for contact person sync', + 'StackiqService: Missing Voorzieningen configuration for contact person sync', [ 'organizationUuid' => $organizationUuid, 'contactSchemaId' => $contactSchemaId, @@ -3225,7 +3225,7 @@ public function syncContactPersonUsernamesWithOrganization(string $organizationU ); $this->_logger->info( - 'SoftwareCatalogueService: Found contact persons for synchronization', + 'StackiqService: Found contact persons for synchronization', [ 'organizationUuid' => $organizationUuid, 'contactPersonCount' => count($contactPersons), @@ -3240,7 +3240,7 @@ public function syncContactPersonUsernamesWithOrganization(string $organizationU if (empty($email) === false) { $contactPersonUsernames[] = $email; $this->_logger->info( - 'SoftwareCatalogueService: Found contact person username', + 'StackiqService: Found contact person username', [ 'username' => $email, 'contactPersonId' => $contactPerson->getId(), @@ -3253,7 +3253,7 @@ public function syncContactPersonUsernamesWithOrganization(string $organizationU $organisationMapper = $this->getOrganisationMapper(); if ($organisationMapper === null) { $this->_logger->error( - 'SoftwareCatalogueService: OpenRegister OrganisationMapper not available for synchronization', + 'StackiqService: OpenRegister OrganisationMapper not available for synchronization', [ 'organizationUuid' => $organizationUuid, ] @@ -3265,7 +3265,7 @@ public function syncContactPersonUsernamesWithOrganization(string $organizationU if ($organisation === null) { $this->_logger->error( - 'SoftwareCatalogueService: Organization entity not found for synchronization', + 'StackiqService: Organization entity not found for synchronization', [ 'organizationUuid' => $organizationUuid, ] @@ -3279,7 +3279,7 @@ public function syncContactPersonUsernamesWithOrganization(string $organizationU $allUsers = array_unique($allUsers); $this->_logger->info( - 'SoftwareCatalogueService: Updating organization entity users', + 'StackiqService: Updating organization entity users', [ 'organizationUuid' => $organizationUuid, 'currentUsers' => $currentUsers, @@ -3293,7 +3293,7 @@ public function syncContactPersonUsernamesWithOrganization(string $organizationU $organisationMapper->save($organisation); $this->_logger->info( - 'SoftwareCatalogueService: Successfully synchronized contact person usernames', + 'StackiqService: Successfully synchronized contact person usernames', [ 'organizationUuid' => $organizationUuid, 'totalUsers' => count($allUsers), @@ -3303,7 +3303,7 @@ public function syncContactPersonUsernamesWithOrganization(string $organizationU // Organization entity doesn't exist yet - this can happen due to race conditions. // Log and return gracefully, the organization sync will handle this later. $this->_logger->warning( - 'SoftwareCatalogueService: Organization entity not found during username sync (race condition)', + 'StackiqService: Organization entity not found during username sync (race condition)', [ 'organizationUuid' => $organizationUuid, 'message' => 'Expected during anonymous registration - org entity created after contacts', @@ -3311,7 +3311,7 @@ public function syncContactPersonUsernamesWithOrganization(string $organizationU ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Error synchronizing contact person usernames', + 'StackiqService: Error synchronizing contact person usernames', [ 'organizationUuid' => $organizationUuid, 'error' => $e->getMessage(), @@ -3339,7 +3339,7 @@ private function ensureContactPersonInOrganization(object $contactPersonObject): if ($email === null || $organization === false) { $this->_logger->info( - 'SoftwareCatalogueService: Contact person missing email or organisation', + 'StackiqService: Contact person missing email or organisation', [ 'contactPersonId' => $contactPersonObject->getId(), 'hasEmail' => empty($email) === false, @@ -3353,7 +3353,7 @@ private function ensureContactPersonInOrganization(object $contactPersonObject): $owner = $contactPersonObject->getOwner(); if ($owner === 'system') { $this->_logger->info( - 'SoftwareCatalogueService: Skipping contact person owned by system', + 'StackiqService: Skipping contact person owned by system', [ 'contactPersonId' => $contactPersonObject->getId(), 'username' => $email, @@ -3363,7 +3363,7 @@ private function ensureContactPersonInOrganization(object $contactPersonObject): } $this->_logger->info( - 'SoftwareCatalogueService: Ensuring contact person in organization', + 'StackiqService: Ensuring contact person in organization', [ 'contactPersonId' => $contactPersonObject->getId(), 'username' => $email, @@ -3376,7 +3376,7 @@ private function ensureContactPersonInOrganization(object $contactPersonObject): $organisationMapper = $this->getOrganisationMapper(); if ($organisationMapper === null) { $this->_logger->error( - 'SoftwareCatalogueService: OpenRegister OrganisationMapper not available for contact person', + 'StackiqService: OpenRegister OrganisationMapper not available for contact person', [ 'contactPersonId' => $contactPersonObject->getId(), 'organization' => $organization, @@ -3389,7 +3389,7 @@ private function ensureContactPersonInOrganization(object $contactPersonObject): if ($organisation === null) { $this->_logger->error( - 'SoftwareCatalogueService: Organization entity not found for contact person', + 'StackiqService: Organization entity not found for contact person', [ 'contactPersonId' => $contactPersonObject->getId(), 'organization' => $organization, @@ -3402,7 +3402,7 @@ private function ensureContactPersonInOrganization(object $contactPersonObject): $currentUsers = $organisation->getUsers() ?? []; if (in_array($email, $currentUsers) === true) { $this->_logger->info( - 'SoftwareCatalogueService: Contact person already in organization', + 'StackiqService: Contact person already in organization', [ 'contactPersonId' => $contactPersonObject->getId(), 'username' => $email, @@ -3418,7 +3418,7 @@ private function ensureContactPersonInOrganization(object $contactPersonObject): $organisationMapper->save($organisation); $this->_logger->info( - 'SoftwareCatalogueService: Successfully added contact person to organization', + 'StackiqService: Successfully added contact person to organization', [ 'contactPersonId' => $contactPersonObject->getId(), 'username' => $email, @@ -3430,7 +3430,7 @@ private function ensureContactPersonInOrganization(object $contactPersonObject): // Organization entity doesn't exist yet - this can happen due to race conditions. // Log and return gracefully, the organization sync will handle this later. $this->_logger->warning( - 'SoftwareCatalogueService: Org entity not found (race condition), handled by org sync', + 'StackiqService: Org entity not found (race condition), handled by org sync', [ 'contactPersonId' => $contactPersonObject->getId(), 'username' => $email, @@ -3452,7 +3452,7 @@ private function ensureContactPersonInOrganization(object $contactPersonObject): private function updateOrganizationReferences(object $organizationObject): void { try { $this->_logger->info( - 'SoftwareCatalogueService: Updating organization references', + 'StackiqService: Updating organization references', [ 'objectId' => $organizationObject->getId(), ] @@ -3464,7 +3464,7 @@ private function updateOrganizationReferences(object $organizationObject): void // Get the ObjectService to update objects. $objectService = $this->getObjectService(); if ($objectService === null) { - $this->_logger->error('SoftwareCatalogueService: ObjectService not available for updating references'); + $this->_logger->error('StackiqService: ObjectService not available for updating references'); return; } @@ -3476,7 +3476,7 @@ private function updateOrganizationReferences(object $organizationObject): void $organisationEntityUuid = $organisationEntity->getUuid(); $this->_logger->info( - 'SoftwareCatalogueService: Found organization entity for reference update', + 'StackiqService: Found organization entity for reference update', [ 'organizationObjectUuid' => $organizationUuid, 'organizationEntityUuid' => $organisationEntityUuid, @@ -3484,7 +3484,7 @@ private function updateOrganizationReferences(object $organizationObject): void ); } catch (\OCP\AppFramework\Db\DoesNotExistException $e) { $this->_logger->error( - 'SoftwareCatalogueService: Organization entity not found for reference update', + 'StackiqService: Organization entity not found for reference update', [ 'organizationUuid' => $organizationUuid, ] @@ -3494,7 +3494,7 @@ private function updateOrganizationReferences(object $organizationObject): void // Update the organization object's @self.organisation field. $this->_logger->info( - 'SoftwareCatalogueService: Updating organization object reference', + 'StackiqService: Updating organization object reference', [ 'objectId' => $organizationObject->getId(), 'newOrganisationUuid' => $organisationEntityUuid, @@ -3518,7 +3518,7 @@ private function updateOrganizationReferences(object $organizationObject): void $contactpersonen = $objectData['contactpersonen'] ?? []; foreach ($contactpersonen as $contactUuid) { $this->_logger->info( - 'SoftwareCatalogueService: Updating contact person object reference', + 'StackiqService: Updating contact person object reference', [ 'contactUuid' => $contactUuid, 'newOrganisationUuid' => $organisationEntityUuid, @@ -3526,13 +3526,13 @@ private function updateOrganizationReferences(object $organizationObject): void ); // Get the contact person schema ID from configuration. - $settingsService = $this->_container->get('OCA\SoftwareCatalog\Service\SettingsService'); + $settingsService = $this->_container->get('OCA\Stackiq\Service\SettingsService'); $voorzieningenConfig = $settingsService->getVoorzieningenConfig(); $contactSchemaId = $voorzieningenConfig['contactpersoon_schema'] ?? null; if ($contactSchemaId === null) { $this->_logger->warning( - 'SoftwareCatalogueService: Missing contactpersoon schema configuration for object update', + 'StackiqService: Missing contactpersoon schema configuration for object update', [ 'contactUuid' => $contactUuid, ] @@ -3566,7 +3566,7 @@ private function updateOrganizationReferences(object $organizationObject): void } } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to update contact person object', + 'StackiqService: Failed to update contact person object', [ 'contactUuid' => $contactUuid, 'error' => $e->getMessage(), @@ -3576,7 +3576,7 @@ private function updateOrganizationReferences(object $organizationObject): void }//end foreach $this->_logger->info( - 'SoftwareCatalogueService: Successfully updated organization references', + 'StackiqService: Successfully updated organization references', [ 'organizationUuid' => $organizationUuid, 'organizationEntityUuid' => $organisationEntityUuid, @@ -3585,7 +3585,7 @@ private function updateOrganizationReferences(object $organizationObject): void ); } catch (\Exception $e) { $this->_logger->error( - 'SoftwareCatalogueService: Failed to update organization references: ' . $e->getMessage(), + 'StackiqService: Failed to update organization references: ' . $e->getMessage(), [ 'objectId' => $organizationObject->getId(), 'exception' => $e->getMessage(), @@ -3611,7 +3611,7 @@ private function updateOrganizationReferences(object $organizationObject): void * log line so the per-method bodies no longer carry that boilerplate. * * W31 method-decomposition 2.6 — companion helper for the - * SoftwareCatalogue subservice wiring. + * Stackiq subservice wiring. * * @param string $schemaSlug Object-type slug as understood by * `SettingsService::getSchemaIdForObjectType()` @@ -3633,7 +3633,7 @@ private function resolveVoorzieningenContext(string $schemaSlug, string $logCont if ($registerId === null || $schemaId === null || $schemaId === false) { $this->_logger->error( - 'SoftwareCatalogueService: Register or schema not configured for ' . $logContext + 'StackiqService: Register or schema not configured for ' . $logContext ); return null; } diff --git a/lib/Service/SymfonyEmailService.php b/lib/Service/SymfonyEmailService.php index 8a92fdbd..1a171e9b 100644 --- a/lib/Service/SymfonyEmailService.php +++ b/lib/Service/SymfonyEmailService.php @@ -1,10 +1,10 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 @@ -16,7 +16,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCP\IAppConfig; use Psr\Log\LoggerInterface; @@ -34,7 +34,7 @@ * SendGrid, Mailgun, and other providers. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @link https://codeberg.org/Conduction/SoftwareCatalog diff --git a/lib/Service/ViewQueryBuilder.php b/lib/Service/ViewQueryBuilder.php index ef349e55..705f520e 100644 --- a/lib/Service/ViewQueryBuilder.php +++ b/lib/Service/ViewQueryBuilder.php @@ -1,17 +1,17 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/changes/method-decomposition/tasks.md#task-6 * @@ -21,7 +21,7 @@ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; /** * Builds and applies filters and sorting to view query option arrays. diff --git a/lib/Service/ViewService.php b/lib/Service/ViewService.php index 5104f1b1..21c0db91 100644 --- a/lib/Service/ViewService.php +++ b/lib/Service/ViewService.php @@ -1,25 +1,25 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @spec openspec/specs/method-decomposition/spec.md */ declare(strict_types=1); -namespace OCA\SoftwareCatalog\Service; +namespace OCA\Stackiq\Service; use OCA\OpenRegister\Contract\ObjectServiceInterface; use OCP\App\IAppManager; @@ -37,12 +37,12 @@ * data such as products, usage information (gebruik), and related data. * * @category Service - * @package OCA\SoftwareCatalog\Service + * @package OCA\Stackiq\Service * @author Conduction b.v. * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq * * @SuppressWarnings(PHPMD.ExcessiveClassLength) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) @@ -93,7 +93,7 @@ public function __construct( private readonly IUserSession $userSession, ICacheFactory $cacheFactory, ) { - $this->viewsCache = $cacheFactory->createDistributed(prefix: 'softwarecatalog_views'); + $this->viewsCache = $cacheFactory->createDistributed(prefix: 'stackiq_views'); }//end __construct() /** diff --git a/lib/Settings/SoftwareCatalogAdmin.php b/lib/Settings/StackiqAdmin.php similarity index 87% rename from lib/Settings/SoftwareCatalogAdmin.php rename to lib/Settings/StackiqAdmin.php index bfb06895..c21e8db0 100644 --- a/lib/Settings/SoftwareCatalogAdmin.php +++ b/lib/Settings/StackiqAdmin.php @@ -1,18 +1,18 @@ * @copyright 2024 Conduction B.V. * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version GIT: - * @link https://codeberg.org/Conduction/SoftwareCatalog + * @link https://github.com/ConductionNL/stackiq */ -namespace OCA\SoftwareCatalog\Settings; +namespace OCA\Stackiq\Settings; use OCP\App\IAppManager; use OCP\AppFramework\Http\TemplateResponse; @@ -21,7 +21,7 @@ use OCP\IL10N; use OCP\Settings\IDelegatedSettings; -class SoftwareCatalogAdmin implements IDelegatedSettings { +class StackiqAdmin implements IDelegatedSettings { /** * The localization service. @@ -52,7 +52,7 @@ class SoftwareCatalogAdmin implements IDelegatedSettings { private IInitialState $initialState; /** - * Constructor for SoftwareCatalogAdmin settings. + * Constructor for StackiqAdmin settings. * * @param IAppConfig $config The application configuration service * @param IL10N $l10n The localization service @@ -72,9 +72,9 @@ public function __construct(IAppConfig $config, IL10N $l10n, IAppManager $appMan * @return TemplateResponse The template response for the settings form */ public function getForm(): TemplateResponse { - $this->initialState->provideInitialState('version', $this->appManager->getAppVersion('softwarecatalog')); + $this->initialState->provideInitialState('version', $this->appManager->getAppVersion('stackiq')); - return new TemplateResponse('softwarecatalog', 'settings/admin', []); + return new TemplateResponse('stackiq', 'settings/admin', []); }//end getForm() /** @@ -84,7 +84,7 @@ public function getForm(): TemplateResponse { */ public function getSection(): string { // Name of the previously created section. - $sectionName = 'softwarecatalog'; + $sectionName = 'stackiq'; return $sectionName; }//end getSection() @@ -117,7 +117,7 @@ public function getName(): ?string { /** * App config keys an authorized (delegated) admin may manage. * - * Returned as a map of appId => list of allowed config keys. SoftwareCatalog + * Returned as a map of appId => list of allowed config keys. Stackiq * exposes no delegatable sub-keys, so this is intentionally empty; the * `#[AuthorizedAdminSetting]` attribute still scopes the endpoints to full * admins (fail-closed). Required by IDelegatedSettings — its absence is a diff --git a/lib/Settings/register.d/contracts-to-decidesk.json b/lib/Settings/register.d/contracts-to-decidesk.json index c70c8e48..2097a43f 100644 --- a/lib/Settings/register.d/contracts-to-decidesk.json +++ b/lib/Settings/register.d/contracts-to-decidesk.json @@ -5,7 +5,7 @@ "properties": { "approvalDecisionId": { "type": "string", - "description": "PROJECTION FIELD. The id of the decidesk Decision (decisionType contract / contract-renewal) raised for this contract's approval/sign-off, resolved via the ADR-019 integration registry. Empty until the contract is submitted for approval. softwarecatalog never authors an approval decision locally; it raises it in decidesk and stores the returned id here for outcome reconciliation.", + "description": "PROJECTION FIELD. The id of the decidesk Decision (decisionType contract / contract-renewal) raised for this contract's approval/sign-off, resolved via the ADR-019 integration registry. Empty until the contract is submitted for approval. stackiq never authors an approval decision locally; it raises it in decidesk and stores the returned id here for outcome reconciliation.", "facetable": false, "title": "Approval decision id", "order": 20, @@ -20,7 +20,7 @@ "rejected" ], "default": "none", - "description": "PROJECTION of the decidesk outcome for the approval/renewal decision — distinct from the catalog lifecycle field `status`. `none` = no decision raised; `pending` = a decidesk Decision is open; `approved` = decidesk reported an adopting outcome (this is the ONLY thing that drives the `In onderhandeling -> Actief` transition on `status`); `rejected` = decidesk rejected/withdrew (status stays `In onderhandeling`). softwarecatalog NEVER sets `status = Actief` on its own authority — it is always a projection of an `approved` decidesk outcome. The date-driven `Actief -> Verlopen` expiry transition is catalog-local and is NOT a decision delegated to decidesk.", + "description": "PROJECTION of the decidesk outcome for the approval/renewal decision — distinct from the catalog lifecycle field `status`. `none` = no decision raised; `pending` = a decidesk Decision is open; `approved` = decidesk reported an adopting outcome (this is the ONLY thing that drives the `In onderhandeling -> Actief` transition on `status`); `rejected` = decidesk rejected/withdrew (status stays `In onderhandeling`). stackiq NEVER sets `status = Actief` on its own authority — it is always a projection of an `approved` decidesk outcome. The date-driven `Actief -> Verlopen` expiry transition is catalog-local and is NOT a decision delegated to decidesk.", "facetable": false, "title": "Approval state", "order": 21, diff --git a/lib/Settings/softwarecatalogus_register.json b/lib/Settings/softwarecatalogus_register.json index 39c8db05..ae9c8802 100644 --- a/lib/Settings/softwarecatalogus_register.json +++ b/lib/Settings/softwarecatalogus_register.json @@ -8,7 +8,7 @@ }, "x-openregister": { "type": "application", - "app": "softwarecatalog", + "app": "stackiq", "sourceType": "local", "sourceUrl": "lib/Settings/softwarecatalogus_register.json", "openregister": "^v0.2.10", diff --git a/openapi.json b/openapi.json index 32f1ef47..bd45fa77 100644 --- a/openapi.json +++ b/openapi.json @@ -1,9 +1,9 @@ { "openapi": "3.0.3", "info": { - "title": "softwarecatalog", + "title": "stackiq", "version": "0.1.141-unstable.20260821053703", - "description": "Software Catalog", + "description": "Stackiq", "license": { "name": "agpl" } diff --git a/openspec/changes/adopt-apphost/hydra.json b/openspec/changes/adopt-apphost/hydra.json index ca90dbb2..6dbdd96b 100644 --- a/openspec/changes/adopt-apphost/hydra.json +++ b/openspec/changes/adopt-apphost/hydra.json @@ -1,8 +1,8 @@ { "spec_slug": "adopt-apphost", "title": "Adopt OpenRegister AppHost (observability + boilerplate)", - "app": "softwarecatalog", - "repo": "https://codeberg.org/Conduction/softwarecatalog", + "app": "stackiq", + "repo": "https://codeberg.org/Conduction/stackiq", "depends_on": [ "apphost-observability-engine", "apphost-boilerplate-controllers" diff --git a/openspec/changes/adopt-apphost/proposal.md b/openspec/changes/adopt-apphost/proposal.md index d1633790..6762b723 100644 --- a/openspec/changes/adopt-apphost/proposal.md +++ b/openspec/changes/adopt-apphost/proposal.md @@ -2,11 +2,11 @@ kind: code --- -# Proposal: SoftwareCatalog Adopts OpenRegister AppHost +# Proposal: Stackiq Adopts OpenRegister AppHost ## Problem -SoftwareCatalog is one of the three fleet apps (with larpingapp and zaakafhandelapp) that has **no health or metrics endpoint at all** — a direct ADR-006 violation flagged in the 2026-06-12 fleet observability inventory. Worse, it pretends otherwise: `appinfo/routes.php` carries the comment `// Note: /api/health is served by settings#status above`, but: +Stackiq is one of the three fleet apps (with larpingapp and zaakafhandelapp) that has **no health or metrics endpoint at all** — a direct ADR-006 violation flagged in the 2026-06-12 fleet observability inventory. Worse, it pretends otherwise: `appinfo/routes.php` carries the comment `// Note: /api/health is served by settings#status above`, but: - There is **no `/api/health` route** in the file. The referenced route is `settings#status` at `/api/settings/status`. - `SettingsController::status()` requires an authenticated session (`@NoAdminRequired` + an explicit 401 on anonymous calls) — ADR-006 health must be public for probes. @@ -14,7 +14,7 @@ SoftwareCatalog is one of the three fleet apps (with larpingapp and zaakafhandel So the app's "health" is a pseudo-health: wrong URL, wrong auth posture, wrong shape, wrong semantics. There is no metrics endpoint of any kind. -Beyond observability, SoftwareCatalog carries the full boilerplate set the AppHost replaces: `DashboardController` (100 lines, SPA page + catch-all + trivial `index()` stub), `PreferencesController` (154 lines), the generic settings surface inside the 3,667-line `SettingsController`, `Repair/InitializeSettings`, `Sections/SoftwareCatalogAdmin` + `Settings/SoftwareCatalogAdmin`, a 592-line `Application.php`, and a 217-line hand-maintained `routes.php`. +Beyond observability, Stackiq carries the full boilerplate set the AppHost replaces: `DashboardController` (100 lines, SPA page + catch-all + trivial `index()` stub), `PreferencesController` (154 lines), the generic settings surface inside the 3,667-line `SettingsController`, `Repair/InitializeSettings`, `Sections/StackiqAdmin` + `Settings/StackiqAdmin`, a 592-line `Application.php`, and a 217-line hand-maintained `routes.php`. ## Proposed Change @@ -24,7 +24,7 @@ Adopt both halves of the OpenRegister AppHost (`apphost-observability-engine` + - Add an `observability` block to `src/manifest.json`: - **Health checks**: `database` + `orAvailable` (the app is fully OR-backed; if OR is down the app is down). Engine-owned posture: public, `statusCodePolicy: adr006` (503 on critical failure). - - **Metrics**: implicit `softwarecatalog_info` / `softwarecatalog_up`, plus one example descriptor `gebruik_total` — `objectCount` on register `voorzieningen`, schema `gebruik` (the app's main usage entity; both slugs verified against `lib/Settings/softwarecatalogus_register.json`). Engine-owned: admin-only, Prometheus text 0.0.4. + - **Metrics**: implicit `stackiq_info` / `stackiq_up`, plus one example descriptor `gebruik_total` — `objectCount` on register `voorzieningen`, schema `gebruik` (the app's main usage entity; both slugs verified against `lib/Settings/softwarecatalogus_register.json`). Engine-owned: admin-only, Prometheus text 0.0.4. - Route `/api/health` → `health#check` and `/api/metrics` → `metrics#index` to the AppHost generic controllers via the standard alias wiring. - **Delete the misleading routes.php comment.** `settings#status` keeps existing at `/api/settings/status` and reverts to being exactly what it is: an authenticated settings/configuration-status endpoint. Nothing else changes about it; it simply stops being claimed as health. @@ -36,14 +36,14 @@ Adopt both halves of the OpenRegister AppHost (`apphost-observability-engine` + - **`lib/Controller/SettingsController.php` (3,667 lines) — SCOPED, NOT deleted.** This controller is almost entirely DOMAIN: ~75 methods covering email + email templates, ArchiMate import/export/status/round-trip, organisation sync, user-group management, cronjob config, progress streaming, AMEF/voorzieningen/general/sync focused config endpoints, object counts/statistics, bulk standards sync, heartbeat, version/import/force-update management. **Only the generic settings surface moves**: `index()`, `create()`, and `load()` (the `GenericSettingsController` contract). The class becomes a subclass of `GenericSettingsController` (extension-first, per the AppHost design), deletes those three hand-written bodies, and keeps every domain method — including `status()`, which stays as the domain configuration-status endpoint. - **`lib/Service/SettingsService.php` (6,716 lines) — KEEP.** Same verdict: overwhelmingly domain (register auto-detection heuristics, sync, ArchiMate config). Only the register/schema config-resolution + OR-availability surface overlaps `AppHostSettingsService`; refactoring it to delegate is explicitly out of scope here (tracked as follow-up) to keep this change parity-verifiable. - **`lib/Repair/InitializeSettings.php` → one-line stub** extending `GenericInitializeSettings` (info.xml `` requires an app-namespace class; repair-step pattern preserved per the install-order constraint). -- **`lib/Sections/SoftwareCatalogAdmin.php` + `lib/Settings/SoftwareCatalogAdmin.php` → one-line stubs** extending `GenericSettingsSection` / `GenericAdminSettings` (IDelegatedSettings, #299 pattern). +- **`lib/Sections/StackiqAdmin.php` + `lib/Settings/StackiqAdmin.php` → one-line stubs** extending `GenericSettingsSection` / `GenericAdminSettings` (IDelegatedSettings, #299 pattern). - **No DeepLinkRegistrationListener exists in this app** — nothing to adopt there. -- **`lib/AppInfo/Application.php` (592 lines)**: replace the boilerplate registrations with `Bootstrap::register($context, self::APP_ID)`; the substantial domain wiring stays (SoftwareCatalogue handlers, domain services, OR event listeners, dashboard widget, the `boot()` manifest-sentinel initial-state provisioning). +- **`lib/AppInfo/Application.php` (592 lines)**: replace the boilerplate registrations with `Bootstrap::register($context, self::APP_ID)`; the substantial domain wiring stays (Stackique handlers, domain services, OR event listeners, dashboard widget, the `boot()` manifest-sentinel initial-state provisioning). - **`appinfo/routes.php` (217 lines)**: rebuild on `Routes::standard($extra)` — standard supplies dashboard page + catch-all, settings index/create/load, preferences, health, metrics; the large domain route set (settings domain endpoints, contactpersonen, views, aanbod, aangeboden-gebruik, gebruik, cronjobs) is appended via `$extra`. Route names/URLs/verbs unchanged for everything that exists today. ## Impact -- **New endpoints**: `GET /apps/softwarecatalog/api/health` (public, ADR-006) and `GET /apps/softwarecatalog/api/metrics` (admin, Prometheus) — closing a fleet-inventory compliance gap. +- **New endpoints**: `GET /apps/stackiq/api/health` (public, ADR-006) and `GET /apps/stackiq/api/metrics` (admin, Prometheus) — closing a fleet-inventory compliance gap. - **Deleted**: DashboardController + PreferencesController (~254 lines), 3 generic method bodies in SettingsController, boilerplate Application.php registrations, hand-written standard routes; repair/section/admin-settings classes shrink to stubs. - **Unchanged contracts**: all existing route names, URLs, verbs, response shapes; `settings#status` response is byte-identical; preferences keys keep resolving. - **Risk**: behavioural drift between old copies and the generic classes — mitigated by endpoint-level parity checks (baseline capture in tasks 0.x, OR Newman contract collection, existing e2e suite) before deletion lands. diff --git a/openspec/changes/adopt-apphost/specs/apphost-adoption/spec.md b/openspec/changes/adopt-apphost/specs/apphost-adoption/spec.md index 8597a6e5..fb1d2e90 100644 --- a/openspec/changes/adopt-apphost/specs/apphost-adoption/spec.md +++ b/openspec/changes/adopt-apphost/specs/apphost-adoption/spec.md @@ -2,11 +2,11 @@ status: proposed --- -# SoftwareCatalog AppHost Adoption +# Stackiq AppHost Adoption ## Purpose -SoftwareCatalog serves real ADR-006 observability endpoints (replacing the `settings#status` pseudo-health) and runs its app boilerplate (dashboard SPA serving, preferences, generic settings surface, install/admin plumbing) on the OpenRegister AppHost generics, with endpoint-level parity for everything that exists today. +Stackiq serves real ADR-006 observability endpoints (replacing the `settings#status` pseudo-health) and runs its app boilerplate (dashboard SPA serving, preferences, generic settings surface, install/admin plumbing) on the OpenRegister AppHost generics, with endpoint-level parity for everything that exists today. **Cross-references**: `openregister/openspec/changes/apphost-observability-engine/specs/apphost-observability/spec.md`, `openregister/openspec/changes/apphost-boilerplate-controllers/` @@ -16,65 +16,65 @@ SoftwareCatalog serves real ADR-006 observability endpoints (replacing the `sett ### Requirement: ADR-006 Health Endpoint -SoftwareCatalog SHALL serve `GET /apps/softwarecatalog/api/health` through the AppHost `GenericHealthController` — publicly accessible, executing the manifest-declared `database` and `orAvailable` checks, returning the fleet health shape and HTTP 503 when a critical check fails (`statusCodePolicy: adr006`). +Stackiq SHALL serve `GET /apps/stackiq/api/health` through the AppHost `GenericHealthController` — publicly accessible, executing the manifest-declared `database` and `orAvailable` checks, returning the fleet health shape and HTTP 503 when a critical check fails (`statusCodePolicy: adr006`). #### Scenario: Anonymous health probe on a healthy instance - **GIVEN** a healthy instance with OpenRegister enabled -- **WHEN** `GET /apps/softwarecatalog/api/health` is called without authentication -- **THEN** the response MUST be HTTP 200 with `status = "ok"`, `app = "softwarecatalog"`, and `checks.database = "ok"` and `checks.openregister = "ok"` in the standard `{status, app, version, checks}` shape +- **WHEN** `GET /apps/stackiq/api/health` is called without authentication +- **THEN** the response MUST be HTTP 200 with `status = "ok"`, `app = "stackiq"`, and `checks.database = "ok"` and `checks.openregister = "ok"` in the standard `{status, app, version, checks}` shape - @e2e exclude API-only endpoint — covered by the OR AppHost Newman contract collection #### Scenario: Critical check failure returns 503 - **GIVEN** OpenRegister is disabled or its ObjectService cannot be resolved -- **WHEN** `GET /apps/softwarecatalog/api/health` is called +- **WHEN** `GET /apps/stackiq/api/health` is called - **THEN** the response MUST be HTTP 503 with `status = "error"` and `checks.openregister` reporting `failed: ` without leaking exception details - @e2e exclude API-only endpoint — covered by the OR AppHost Newman contract collection ### Requirement: ADR-006 Metrics Endpoint -SoftwareCatalog SHALL serve `GET /apps/softwarecatalog/api/metrics` through the AppHost `GenericMetricsController` — admin-only, Prometheus text format 0.0.4 — emitting the implicit `softwarecatalog_info` and `softwarecatalog_up` metrics plus the declared `softwarecatalog_gebruik_total` gauge (`objectCount` on register `voorzieningen`, schema `gebruik`). +Stackiq SHALL serve `GET /apps/stackiq/api/metrics` through the AppHost `GenericMetricsController` — admin-only, Prometheus text format 0.0.4 — emitting the implicit `stackiq_info` and `stackiq_up` metrics plus the declared `stackiq_gebruik_total` gauge (`objectCount` on register `voorzieningen`, schema `gebruik`). #### Scenario: Admin scrapes metrics - **GIVEN** a seeded instance with gebruik objects in the voorzieningen register -- **WHEN** `GET /apps/softwarecatalog/api/metrics` is called by an admin -- **THEN** the response MUST be Prometheus text 0.0.4 with `# HELP`/`# TYPE` lines containing `softwarecatalog_info` (version, php_version, nextcloud_version labels), `softwarecatalog_up 1`, and `softwarecatalog_gebruik_total` matching the gebruik object count +- **WHEN** `GET /apps/stackiq/api/metrics` is called by an admin +- **THEN** the response MUST be Prometheus text 0.0.4 with `# HELP`/`# TYPE` lines containing `stackiq_info` (version, php_version, nextcloud_version labels), `stackiq_up 1`, and `stackiq_gebruik_total` matching the gebruik object count - @e2e exclude API-only endpoint — covered by the OR AppHost Newman contract collection #### Scenario: Non-admin is rejected - **GIVEN** an authenticated non-admin user -- **WHEN** `GET /apps/softwarecatalog/api/metrics` is called +- **WHEN** `GET /apps/stackiq/api/metrics` is called - **THEN** the request MUST be rejected (401/403) by the engine-owned admin posture - @e2e exclude API-only endpoint — covered by the OR AppHost Newman contract collection ### Requirement: Pseudo-Health Retirement -SoftwareCatalog SHALL remove the claim that `settings#status` serves health: the `// Note: /api/health is served by settings#status above` comment in `appinfo/routes.php` SHALL be deleted, while `GET /api/settings/status` SHALL keep serving its current authenticated configuration-status response unchanged (`{status, fullyConfigured, versionInfo, timestamp, autoConfigCompleted}`). +Stackiq SHALL remove the claim that `settings#status` serves health: the `// Note: /api/health is served by settings#status above` comment in `appinfo/routes.php` SHALL be deleted, while `GET /api/settings/status` SHALL keep serving its current authenticated configuration-status response unchanged (`{status, fullyConfigured, versionInfo, timestamp, autoConfigCompleted}`). #### Scenario: Settings status is unchanged and is not health - **GIVEN** an authenticated user on a configured instance -- **WHEN** `GET /apps/softwarecatalog/api/settings/status` is called +- **WHEN** `GET /apps/stackiq/api/settings/status` is called - **THEN** the response MUST be byte-identical to the pre-adoption baseline, and anonymous calls MUST still receive 401 — the endpoint is a settings endpoint, distinct from the public `/api/health` - @e2e exclude API-only endpoint — covered by the OR AppHost Newman contract collection ### Requirement: Boilerplate Runs on AppHost Generics -SoftwareCatalog SHALL serve its SPA (dashboard page + catch-all), per-user preferences, and the generic settings surface (`settings#index`, `settings#create`, `settings#load`) through the AppHost generic controllers via alias wiring (`Bootstrap::register`) and `Routes::standard($extra)`, deleting `DashboardController` and `PreferencesController` and the three generic `SettingsController` method bodies. All domain surfaces SHALL remain app-owned: `ViewController` (ArchiMate view-enrichment API), the ~75 domain methods of `SettingsController`, `SettingsService`, and all domain routes appended via `$extra` with unchanged names, URLs, and verbs. +Stackiq SHALL serve its SPA (dashboard page + catch-all), per-user preferences, and the generic settings surface (`settings#index`, `settings#create`, `settings#load`) through the AppHost generic controllers via alias wiring (`Bootstrap::register`) and `Routes::standard($extra)`, deleting `DashboardController` and `PreferencesController` and the three generic `SettingsController` method bodies. All domain surfaces SHALL remain app-owned: `ViewController` (ArchiMate view-enrichment API), the ~75 domain methods of `SettingsController`, `SettingsService`, and all domain routes appended via `$extra` with unchanged names, URLs, and verbs. #### Scenario: SPA still renders after dashboard aliasing - **GIVEN** the app is enabled and a user is logged in -- **WHEN** the user opens `/apps/softwarecatalog/` or deep-links to any frontend route such as `/apps/softwarecatalog/voorzieningen` +- **WHEN** the user opens `/apps/stackiq/` or deep-links to any frontend route such as `/apps/stackiq/voorzieningen` - **THEN** the Vue SPA MUST render via the generic dashboard controller serving `templates/index.php` with the preserved chunk-loading order, and in-app navigation MUST work as before #### Scenario: Preferences parity through the generic controller - **GIVEN** a user with a preference previously written by the hand-written controller -- **WHEN** `GET /apps/softwarecatalog/api/preferences/{key}` and `PUT` with a new value are called +- **WHEN** `GET /apps/stackiq/api/preferences/{key}` and `PUT` with a new value are called - **THEN** the stored value MUST resolve under the same key namespace and the response shapes MUST match the pre-adoption baseline - @e2e exclude API-only endpoint — covered by the OR AppHost Newman contract collection @@ -87,7 +87,7 @@ SoftwareCatalog SHALL serve its SPA (dashboard page + catch-all), per-user prefe ### Requirement: Install And Admin Plumbing Via Stubs -SoftwareCatalog SHALL keep `Repair/InitializeSettings`, `Sections/SoftwareCatalogAdmin`, and `Settings/SoftwareCatalogAdmin` only as one-line app-namespace stubs extending the AppHost generics (required by info.xml ``/`` registration), preserving the repair-step install pattern and the IDelegatedSettings (#299) admin-settings pattern. +Stackiq SHALL keep `Repair/InitializeSettings`, `Sections/StackiqAdmin`, and `Settings/StackiqAdmin` only as one-line app-namespace stubs extending the AppHost generics (required by info.xml ``/`` registration), preserving the repair-step install pattern and the IDelegatedSettings (#299) admin-settings pattern. #### Scenario: Register import still runs on install/upgrade diff --git a/openspec/changes/adopt-apphost/tasks.md b/openspec/changes/adopt-apphost/tasks.md index 24475377..8b9655f7 100644 --- a/openspec/changes/adopt-apphost/tasks.md +++ b/openspec/changes/adopt-apphost/tasks.md @@ -1,29 +1,29 @@ -# Tasks: SoftwareCatalog Adopts OpenRegister AppHost +# Tasks: Stackiq Adopts OpenRegister AppHost ## 0. Baseline -- [ ] 0.1 Capture baseline of the pseudo-health: `curl` (authenticated) `GET /apps/softwarecatalog/api/settings/status` on the dev instance; store the JSON (`{status, fullyConfigured, versionInfo, timestamp, autoConfigCompleted}`) as a parity fixture — this endpoint must be byte-identical after adoption +- [ ] 0.1 Capture baseline of the pseudo-health: `curl` (authenticated) `GET /apps/stackiq/api/settings/status` on the dev instance; store the JSON (`{status, fullyConfigured, versionInfo, timestamp, autoConfigCompleted}`) as a parity fixture — this endpoint must be byte-identical after adoption - [ ] 0.2 Record the current state for the change log: NO `/api/health` or `/api/metrics` route exists; `appinfo/routes.php` line ~69 carries the false comment `// Note: /api/health is served by settings#status above` - [ ] 0.3 Capture baseline responses of `dashboard#page` (SPA template), `dashboard#index`, and `preferences#getPreference`/`setPreference` for parity diff after generic-controller aliasing ## 1. Manifest observability block -- [ ] 1.1 Add `observability` to `src/manifest.json`: `health.checks = [{id: database, type: database}, {id: openregister, type: orAvailable}]` (default `statusCodePolicy: adr006`); `metrics = [{name: gebruik_total, type: gauge, help: "Gebruik (usage) records", source: {kind: objectCount, register: voorzieningen, schema: gebruik}}]` — implicit `softwarecatalog_info`/`softwarecatalog_up` come free +- [ ] 1.1 Add `observability` to `src/manifest.json`: `health.checks = [{id: database, type: database}, {id: openregister, type: orAvailable}]` (default `statusCodePolicy: adr006`); `metrics = [{name: gebruik_total, type: gauge, help: "Gebruik (usage) records", source: {kind: objectCount, register: voorzieningen, schema: gebruik}}]` — implicit `stackiq_info`/`stackiq_up` come free - [ ] 1.2 Validate the block via ManifestService diagnostics (no errors); confirm `voorzieningen`/`gebruik` slugs resolve against the imported register ## 2. Wiring, deletions, real health/metrics routes -- [ ] 2.1 `lib/AppInfo/Application.php`: add `Bootstrap::register($context, self::APP_ID)`; remove the boilerplate registrations it supersedes; KEEP all domain wiring (SoftwareCatalogue handlers, domain services, OR event listeners, ConceptOrganisatiesWidget, `boot()` initial-state sentinel provisioning) +- [ ] 2.1 `lib/AppInfo/Application.php`: add `Bootstrap::register($context, self::APP_ID)`; remove the boilerplate registrations it supersedes; KEEP all domain wiring (Stackique handlers, domain services, OR event listeners, ConceptOrganisatiesWidget, `boot()` initial-state sentinel provisioning) - [ ] 2.2 `appinfo/routes.php`: rebuild on `\OCA\OpenRegister\AppHost\Routes::standard($extra)` — standard provides dashboard page + SPA catch-all, settings index/create/load, preferences GET/PUT, **`/api/health` (public) and `/api/metrics` (admin)**; append all domain routes via `$extra` with names/URLs/verbs unchanged; DELETE the `// Note: /api/health is served by settings#status above` comment - [ ] 2.3 DELETE `lib/Controller/DashboardController.php` (SPA server → `GenericDashboardController` alias) and `lib/Controller/PreferencesController.php` (→ `GenericPreferencesController` alias) - [ ] 2.4 `lib/Controller/SettingsController.php`: extend `GenericSettingsController`; delete ONLY the hand-written `index()`, `create()`, `load()` bodies; keep all ~75 domain methods (email, ArchiMate, sync, user groups, cronjobs, progress, focused configs, counts/statistics, heartbeat, version/import management) — including `status()`, which reverts to being just the settings configuration-status endpoint -- [ ] 2.5 Shrink `lib/Repair/InitializeSettings.php`, `lib/Sections/SoftwareCatalogAdmin.php`, `lib/Settings/SoftwareCatalogAdmin.php` to one-line stubs extending the AppHost generics (info.xml ``/`` require app-namespace classes); confirm no DeepLinkRegistrationListener exists to adopt +- [ ] 2.5 Shrink `lib/Repair/InitializeSettings.php`, `lib/Sections/StackiqAdmin.php`, `lib/Settings/StackiqAdmin.php` to one-line stubs extending the AppHost generics (info.xml ``/`` require app-namespace classes); confirm no DeepLinkRegistrationListener exists to adopt - [ ] 2.6 KEEP `lib/Controller/ViewController.php` (domain ArchiMate view-enrichment API, not the SPA server) and `lib/Service/SettingsService.php` (domain; AppHostSettingsService delegation is a tracked follow-up) untouched - [ ] 2.7 Sweep references: unit tests, `@spec` tags, frontend callers of deleted controller methods (none expected — routes unchanged) ## 3. Verification -- [ ] 3.1 Run the OR AppHost Newman contract collection against softwarecatalog: `/api/health` anonymous 200 with `checks.database`/`checks.openregister`; 503 when a critical check fails; `/api/metrics` admin-only (401/403 for non-admin), Prometheus text 0.0.4 containing `softwarecatalog_info`, `softwarecatalog_up`, `softwarecatalog_gebruik_total` +- [ ] 3.1 Run the OR AppHost Newman contract collection against stackiq: `/api/health` anonymous 200 with `checks.database`/`checks.openregister`; 503 when a critical check fails; `/api/metrics` admin-only (401/403 for non-admin), Prometheus text 0.0.4 containing `stackiq_info`, `stackiq_up`, `stackiq_gebruik_total` - [ ] 3.2 Diff `settings#status`, dashboard, and preferences responses against the 0.x baselines — byte-identical (document any intentional delta; expected: none) - [ ] 3.3 Existing Playwright e2e suite green (SPA catch-all + deep links still render); PHPUnit green diff --git a/openspec/changes/adopt-integration-leaves/proposal.md b/openspec/changes/adopt-integration-leaves/proposal.md index cb5a77c8..569ff8aa 100644 --- a/openspec/changes/adopt-integration-leaves/proposal.md +++ b/openspec/changes/adopt-integration-leaves/proposal.md @@ -3,7 +3,7 @@ kind: code depends_on: [] --- -# softwarecatalog — adopt OpenRegister integration leaves (contacts, calendar, deck, bookmarks) +# stackiq — adopt OpenRegister integration leaves (contacts, calendar, deck, bookmarks) ## Why diff --git a/openspec/changes/beta-surface-alignment/proposal.md b/openspec/changes/beta-surface-alignment/proposal.md index 52e14ac0..55b2f2d4 100644 --- a/openspec/changes/beta-surface-alignment/proposal.md +++ b/openspec/changes/beta-surface-alignment/proposal.md @@ -2,14 +2,14 @@ kind: docs --- -# Proposal: Beta Cross-Surface Alignment — SoftwareCatalog +# Proposal: Beta Cross-Surface Alignment — Stackiq ## Problem -Four surfaces describe SoftwareCatalog (`appinfo/info.xml`, `src/manifest.json`, the conduction.nl product page, and `docs/`) and they disagreed badly enough to block a beta release: +Four surfaces describe Stackiq (`appinfo/info.xml`, `src/manifest.json`, the conduction.nl product page, and `docs/`) and they disagreed badly enough to block a beta release: 1. **License tag wrong.** `appinfo/info.xml` declared `agpl` even though the shipped `LICENSE` file is the European Union Public Licence v1.2 and the description text already said "EUPL". Many PHP/Vue/JS file headers also carry `SPDX-License-Identifier: AGPL-3.0-or-later` — a pre-existing, wider inconsistency noted below but not touched in this change (see "Deferred"). -2. **The product page (`conduction-website/src/pages/apps/softwarecatalog.mdx` + its NL translation) was substantially fabricated.** It described an app that pulls IT-asset inventory from Microsoft Intune/Jamf/GLPI/OCS Inventory via OpenConnector, computes a "dependency graph" with "deprecation impact" analysis, federates specifically to Forum Standaardisatie/data.overheid.nl, and ships dashboard widgets named "Renewals due", "Inventory snapshot" and "Discovery deltas". None of this exists in `lib/` or `src/`. The page also claimed version `v1.1` / status "Stable" against an actual `info.xml` version of `0.2.13`. +2. **The product page (`conduction-website/src/pages/apps/stackiq.mdx` + its NL translation) was substantially fabricated.** It described an app that pulls IT-asset inventory from Microsoft Intune/Jamf/GLPI/OCS Inventory via OpenConnector, computes a "dependency graph" with "deprecation impact" analysis, federates specifically to Forum Standaardisatie/data.overheid.nl, and ships dashboard widgets named "Renewals due", "Inventory snapshot" and "Discovery deltas". None of this exists in `lib/` or `src/`. The page also claimed version `v1.1` / status "Stable" against an actual `info.xml` version of `0.2.13`. 3. **`docs/FEATURES.md` was stale** (missing contracts, standards/compliance matrix, ArchiMate, portfolio roadmap, reviews, moderated self-registration — all real, shipped features) though not fabricated. 4. **`docs/GOVERNMENT-FEATURES.md`** (a VNG-style requirements checklist) was largely accurate and unusually self-critical, but repeated the wrong license (`AGPL`) and an outdated attribution (`GitHub` instead of Codeberg). @@ -43,9 +43,9 @@ Four surfaces describe SoftwareCatalog (`appinfo/info.xml`, `src/manifest.json`, ## Fixes Applied 1. `appinfo/info.xml`: `agpl` → `EUPL-1.2`; EN+NL description "Key Features" lists expanded to include contract administration, GEMMA/ArchiMate standards & compliance, portfolio roadmap, and moderated open-data publishing; federated-sync bullet reworded to name OpenCatalogi as the optional delegate. -2. `conduction-website/src/pages/apps/softwarecatalog.mdx` (EN) and the NL i18n copy: hero (version, status), intro, FeatureList, RotatingCards, WidgetShelf, Showcase, PairRow, and CtaBanner rewritten around the verified feature list; all fabricated claims removed. -3. `softwarecatalog/docs/FEATURES.md`: added Contract Administration, Standards/Compliance Matrix/ArchiMate, Application Lifecycle & Portfolio Roadmap, Reviews, and Open Data Publishing & Moderated Self-Registration sections; Federated Synchronization section reworded to name OpenCatalogi. -4. `softwarecatalog/docs/GOVERNMENT-FEATURES.md`: license line and open-source attribution corrected (AGPL→EUPL-1.2, GitHub→Codeberg). +2. `conduction-website/src/pages/apps/stackiq.mdx` (EN) and the NL i18n copy: hero (version, status), intro, FeatureList, RotatingCards, WidgetShelf, Showcase, PairRow, and CtaBanner rewritten around the verified feature list; all fabricated claims removed. +3. `stackiq/docs/FEATURES.md`: added Contract Administration, Standards/Compliance Matrix/ArchiMate, Application Lifecycle & Portfolio Roadmap, Reviews, and Open Data Publishing & Moderated Self-Registration sections; Federated Synchronization section reworded to name OpenCatalogi. +4. `stackiq/docs/GOVERNMENT-FEATURES.md`: license line and open-source attribution corrected (AGPL→EUPL-1.2, GitHub→Codeberg). 5. Icon (`img/app.svg`): checked against the brand convention (24×24 viewBox, single `#fff` fill) — already compliant, no change needed. ## Deferred (flagged, not fixed in this change) @@ -56,4 +56,4 @@ Four surfaces describe SoftwareCatalog (`appinfo/info.xml`, `src/manifest.json`, ## Note on Scope -softwarecatalog is a VNG client repository (`Softwarecatalogus/` external client is separate and untouched). All edits in this change are local — no push, no PR, per repo convention for this app. +stackiq is a VNG client repository (`Softwarecatalogus/` external client is separate and untouched). All edits in this change are local — no push, no PR, per repo convention for this app. diff --git a/openspec/changes/beta-surface-alignment/specs/beta-alignment/spec.md b/openspec/changes/beta-surface-alignment/specs/beta-alignment/spec.md index 770dc5af..ec41f323 100644 --- a/openspec/changes/beta-surface-alignment/specs/beta-alignment/spec.md +++ b/openspec/changes/beta-surface-alignment/specs/beta-alignment/spec.md @@ -2,11 +2,11 @@ status: proposed --- -# SoftwareCatalog Beta Cross-Surface Alignment +# Stackiq Beta Cross-Surface Alignment ## Purpose -SoftwareCatalog's code metadata (`appinfo/info.xml`), product page (conduction.nl), and docs (softwarecatalog.conduction.nl) SHALL describe the same, code-verified feature set and licence, so the app is beta-release-ready. +Stackiq's code metadata (`appinfo/info.xml`), product page (conduction.nl), and docs (softwarecatalog.conduction.nl) SHALL describe the same, code-verified feature set and licence, so the app is beta-release-ready. ## Requirements diff --git a/openspec/changes/beta-surface-alignment/tasks.md b/openspec/changes/beta-surface-alignment/tasks.md index 6dceeede..b422ac0f 100644 --- a/openspec/changes/beta-surface-alignment/tasks.md +++ b/openspec/changes/beta-surface-alignment/tasks.md @@ -1,4 +1,4 @@ -# Tasks: Beta Cross-Surface Alignment — SoftwareCatalog +# Tasks: Beta Cross-Surface Alignment — Stackiq ## 1. Derive canonical feature vocabulary @@ -16,14 +16,14 @@ ## 3. Reconcile product page (conduction-website) -- [x] 3.1 Rewrite `src/pages/apps/softwarecatalog.mdx` hero: version `v0.2` (was `v1.1`), status Beta (was Stable) +- [x] 3.1 Rewrite `src/pages/apps/stackiq.mdx` hero: version `v0.2` (was `v1.1`), status Beta (was Stable) - [x] 3.2 Rewrite intro paragraph and `FeatureList` around the verified feature list - [x] 3.3 Rewrite `RotatingCards` (Register / Assess / Federate) removing OpenConnector-discovery and Forum Standaardisatie claims - [x] 3.4 Rewrite `WidgetShelf` to the two real dashboard widgets (object statistics, management information) - [x] 3.5 Rewrite `Showcase` (contract approval, standards/ArchiMate, OpenCatalogi federation) - [x] 3.6 Rewrite `PairRow` — drop OpenConnector and LaunchPad (no code support), keep OpenRegister (hard dependency) + OpenCatalogi (optional) - [x] 3.7 Rewrite `CtaBanner` copy -- [x] 3.8 Mirror all of the above in the NL i18n page (`i18n/nl/docusaurus-plugin-content-pages/apps/softwarecatalog.mdx`) +- [x] 3.8 Mirror all of the above in the NL i18n page (`i18n/nl/docusaurus-plugin-content-pages/apps/stackiq.mdx`) ## 4. Reconcile docs diff --git a/openspec/changes/bound-unbounded-searchobjects-scans/proposal.md b/openspec/changes/bound-unbounded-searchobjects-scans/proposal.md index a53dad7c..9f52281b 100644 --- a/openspec/changes/bound-unbounded-searchobjects-scans/proposal.md +++ b/openspec/changes/bound-unbounded-searchobjects-scans/proposal.md @@ -3,7 +3,7 @@ kind: code depends_on: [] --- -# softwarecatalog — bound unbounded `searchObjects()` full-table scans +# stackiq — bound unbounded `searchObjects()` full-table scans ## Why @@ -17,7 +17,7 @@ opposite failure mode from the more common "default-limit truncates results" bug: here, forgetting `_limit` silently removes the safety net. A repo-wide audit of every non-test `searchObjects()` call site in -`softwarecatalog/lib/` found **25 of 29 call sites never set `_limit`** +`stackiq/lib/` found **25 of 29 call sites never set `_limit`** (verified by grepping the 20 lines preceding each call for `_limit`; the 4 exceptions are `ArchiMateService.php:378/397/412/435`, which do set an explicit `_limit`). These are full, unbounded register/schema scans on diff --git a/openspec/changes/bound-unbounded-searchobjects-scans/specs/query-performance/spec.md b/openspec/changes/bound-unbounded-searchobjects-scans/specs/query-performance/spec.md index 75f26c06..a5656bf1 100644 --- a/openspec/changes/bound-unbounded-searchobjects-scans/specs/query-performance/spec.md +++ b/openspec/changes/bound-unbounded-searchobjects-scans/specs/query-performance/spec.md @@ -1,7 +1,7 @@ ## ADDED Requirements ### Requirement: Every `searchObjects()` call MUST set an explicit `_limit` -Every call to `OCA\OpenRegister\Service\ObjectService::searchObjects()` from softwarecatalog's `lib/` MUST pass an explicit `_limit` key in its query array. +Every call to `OCA\OpenRegister\Service\ObjectService::searchObjects()` from stackiq's `lib/` MUST pass an explicit `_limit` key in its query array. Omitting `_limit` causes `MagicSearchHandler::searchObjects()` to call `setMaxResults(null)`, which removes the LIMIT clause entirely and fetches every row in the target register/schema table into PHP memory. diff --git a/openspec/changes/bundle-hygiene-apexcharts-lodash/proposal.md b/openspec/changes/bundle-hygiene-apexcharts-lodash/proposal.md index fc60ac43..a4018013 100644 --- a/openspec/changes/bundle-hygiene-apexcharts-lodash/proposal.md +++ b/openspec/changes/bundle-hygiene-apexcharts-lodash/proposal.md @@ -3,7 +3,7 @@ kind: code depends_on: [] --- -# softwarecatalog — drop unused own `apexcharts` dependency, scope `lodash` imports +# stackiq — drop unused own `apexcharts` dependency, scope `lodash` imports ## Why @@ -13,17 +13,17 @@ resolves to `3.54.1` (`node_modules/apexcharts/package.json`). A repo-wide grep for `apexcharts` under `src/` returns **zero matches** — the app never imports it directly, and `CnChartWidget` (nc-vue's chart component, which does depend on apexcharts) is never used either. Meanwhile -`@conduction/nextcloud-vue` — which softwarecatalog already depends on — +`@conduction/nextcloud-vue` — which stackiq already depends on — ships its own `apexcharts@^4.7.0` (`node_modules/@conduction/nextcloud-vue/package.json`), nested at `node_modules/@conduction/nextcloud-vue/node_modules/apexcharts` because the major-version ranges (`^3.50.0` vs `^4.7.0`) don't overlap and npm cannot dedupe them. Per the fleet convention ("apexcharts from nc-vue, not -duplicated"), softwarecatalog is shipping a second, unused, mismatched +duplicated"), stackiq is shipping a second, unused, mismatched copy of a large charting library (~500KB+ minified) in its own dependency tree for no functional benefit — pure bundle/install-size bloat. -**Unscoped `lodash` imports.** softwarecatalog depends on the full +**Unscoped `lodash` imports.** stackiq depends on the full `lodash` package (`package.json`) but only uses two functions from it: - `src/modals/object/ObjectModal.vue:226` — `import _ from 'lodash'`, @@ -38,7 +38,7 @@ single-function call sites. ## What Changes -- Remove `"apexcharts"` from softwarecatalog's own `package.json` +- Remove `"apexcharts"` from stackiq's own `package.json` dependencies. The app has no direct usage; if a future feature needs charting, it MUST use nc-vue's `CnChartWidget` (which already brings its own apexcharts) rather than re-adding a direct dependency. diff --git a/openspec/changes/bundle-hygiene-apexcharts-lodash/specs/frontend-bundle-hygiene/spec.md b/openspec/changes/bundle-hygiene-apexcharts-lodash/specs/frontend-bundle-hygiene/spec.md index 725ebd2a..52ec6339 100644 --- a/openspec/changes/bundle-hygiene-apexcharts-lodash/specs/frontend-bundle-hygiene/spec.md +++ b/openspec/changes/bundle-hygiene-apexcharts-lodash/specs/frontend-bundle-hygiene/spec.md @@ -1,25 +1,25 @@ ## ADDED Requirements ### Requirement: No duplicate charting library dependency -softwarecatalog's own `package.json` MUST NOT declare a direct dependency +stackiq's own `package.json` MUST NOT declare a direct dependency on `apexcharts` (or any other charting library already provided by `@conduction/nextcloud-vue`'s `CnChartWidget`) unless the app directly imports and uses it. Charting needs MUST be satisfied via nc-vue's shared component so only one version of the library is ever bundled fleet-wide. #### Scenario: No direct apexcharts usage exists -- GIVEN softwarecatalog's `src/` tree contains no direct `apexcharts` +- GIVEN stackiq's `src/` tree contains no direct `apexcharts` import and no usage of `CnChartWidget` - WHEN `package.json` is inspected - THEN it MUST NOT list `apexcharts` as a dependency #### Scenario: A future feature needs a chart -- GIVEN a developer wants to add a chart to softwarecatalog +- GIVEN a developer wants to add a chart to stackiq - WHEN they implement the widget - THEN they MUST use nc-vue's `CnChartWidget` (which supplies its own apexcharts dependency) - AND MUST NOT add a second, separately-versioned `apexcharts` dependency - to softwarecatalog's own `package.json` + to stackiq's own `package.json` ### Requirement: Utility library imports MUST be scoped to the function used Where only one or two functions from a large CJS utility library (e.g. `lodash`) are used, the import MUST reference the specific submodule (`lodash/cloneDeep`, `lodash/debounce`) rather than the package barrel. diff --git a/openspec/changes/bundle-hygiene-apexcharts-lodash/tasks.md b/openspec/changes/bundle-hygiene-apexcharts-lodash/tasks.md index 5b69e9d8..9b68cd9d 100644 --- a/openspec/changes/bundle-hygiene-apexcharts-lodash/tasks.md +++ b/openspec/changes/bundle-hygiene-apexcharts-lodash/tasks.md @@ -26,7 +26,7 @@ ## 3. Verification - [ ] 3.1 `npm run build` — confirm the production bundle no longer - includes a top-level `apexcharts` chunk from softwarecatalog's own + includes a top-level `apexcharts` chunk from stackiq's own dependency (only nc-vue's nested copy, if any chart widget pulls it in transitively). - [ ] 3.2 Run existing vitest suite (`npm run test:unit` or equivalent) to diff --git a/openspec/changes/contract-approval-ownership-guard/proposal.md b/openspec/changes/contract-approval-ownership-guard/proposal.md index 3be20c6f..cd3a9783 100644 --- a/openspec/changes/contract-approval-ownership-guard/proposal.md +++ b/openspec/changes/contract-approval-ownership-guard/proposal.md @@ -3,7 +3,7 @@ kind: code depends_on: [] --- -# softwarecatalog — contract approval per-object ownership guard (IDOR fix) +# stackiq — contract approval per-object ownership guard (IDOR fix) ## Why diff --git a/openspec/changes/i18n-wrap-hardcoded-object-modal-strings/proposal.md b/openspec/changes/i18n-wrap-hardcoded-object-modal-strings/proposal.md index 7928b508..cf76a576 100644 --- a/openspec/changes/i18n-wrap-hardcoded-object-modal-strings/proposal.md +++ b/openspec/changes/i18n-wrap-hardcoded-object-modal-strings/proposal.md @@ -3,12 +3,12 @@ kind: code depends_on: [] --- -# softwarecatalog — wrap hardcoded English UI strings in `t()` across object-action modals and ArchiMate settings +# stackiq — wrap hardcoded English UI strings in `t()` across object-action modals and ArchiMate settings ## Why ADR-004 requires ALL user-visible strings to go through -`t(appName, 'text')` so `l10n/nl.json` can translate them. softwarecatalog +`t(appName, 'text')` so `l10n/nl.json` can translate them. stackiq already runs its own translation-key tooling (`npm run test:l10n` → `tests/l10n/check-l10n.js` / `check-l10n-parity.js`), and that tooling reports 0 problems — but it only @@ -17,7 +17,7 @@ have full-locale parity. It cannot detect prose that was never wrapped in `t()` at all, so a large amount of user-visible English text ships untranslatable regardless of the user's chosen NC locale. -A repo-wide scan (`grep -c "t('softwarecatalog'" per .vue file`) found +A repo-wide scan (`grep -c "t('stackiq'" per .vue file`) found **31 `.vue` files over 50 lines with zero `t()` calls**. Spot-checks confirm these are not trivial wrapper components — they contain real, user-facing prose: @@ -62,7 +62,7 @@ prose: `CollapsibleSection.vue`, `StandardTabs.vue`, `Configuration.vue`, `DirectorySideBar.vue`, `SearchSideBar.vue`). -Net effect: a Dutch-locale user of softwarecatalog sees English text +Net effect: a Dutch-locale user of stackiq sees English text throughout the object-merge/upload/migration/mass-action modals and most of the admin settings screens — the exact silent English-fallback failure mode this sweep's i18n lens targets, just not via missing translation @@ -72,7 +72,7 @@ turned into a key at all. ## What Changes - Wrap every user-visible literal string in the files above in - `t('softwarecatalog', '…')` (interpolated values via the standard `t()` + `t('stackiq', '…')` (interpolated values via the standard `t()` placeholder syntax where needed), following the same convention already used correctly elsewhere in the app (e.g. `ComplianceMatrixView.vue`, `PaginationComponent.vue`). diff --git a/openspec/changes/i18n-wrap-hardcoded-object-modal-strings/specs/fe-object-modals/spec.md b/openspec/changes/i18n-wrap-hardcoded-object-modal-strings/specs/fe-object-modals/spec.md index 44c1898b..0605539a 100644 --- a/openspec/changes/i18n-wrap-hardcoded-object-modal-strings/specs/fe-object-modals/spec.md +++ b/openspec/changes/i18n-wrap-hardcoded-object-modal-strings/specs/fe-object-modals/spec.md @@ -1,7 +1,7 @@ ## ADDED Requirements ### Requirement: Object-action modal text MUST be translatable -Every user-visible string rendered by the object-action modal family (`src/modals/object/*.vue`, `src/modals/BulkSyncDialog.vue`) and the ArchiMate import/export settings section (`src/views/settings/sections/ArchiMateImportExport.vue`) MUST be wrapped in `t('softwarecatalog', '…')` with the English literal as the translation key, per ADR-004. +Every user-visible string rendered by the object-action modal family (`src/modals/object/*.vue`, `src/modals/BulkSyncDialog.vue`) and the ArchiMate import/export settings section (`src/views/settings/sections/ArchiMateImportExport.vue`) MUST be wrapped in `t('stackiq', '…')` with the English literal as the translation key, per ADR-004. No literal English prose (headings, table headers, button labels, empty-state text, placeholders) MAY be rendered directly in a `
+
blocks. The ESLint rule vue/enforce-style-attribute diff --git a/src/components/ContactpersonenList.vue b/src/components/ContactpersonenList.vue index 47a5f894..e6fd23a6 100644 --- a/src/components/ContactpersonenList.vue +++ b/src/components/ContactpersonenList.vue @@ -2,7 +2,7 @@
- {{ t('softwarecatalog', 'Loading contactpersonen...') }} + {{ t('stackiq', 'Loading contactpersonen...') }}
@@ -13,9 +13,9 @@
{{ contactpersoon.loading - ? t('softwarecatalog', 'Converting...') - : t('softwarecatalog', 'Convert to User') + ? t('stackiq', 'Converting...') + : t('stackiq', 'Convert to User') }} @@ -116,7 +116,7 @@ - {{ t('softwarecatalog', 'Change Password') }} + {{ t('stackiq', 'Change Password') }} @@ -127,7 +127,7 @@ - {{ t('softwarecatalog', 'Manage Groups') }} + {{ t('stackiq', 'Manage Groups') }} @@ -141,7 +141,7 @@ - {{ t('softwarecatalog', 'Disable User') }} + {{ t('stackiq', 'Disable User') }} @@ -155,7 +155,7 @@ - {{ t('softwarecatalog', 'Enable User') }} + {{ t('stackiq', 'Enable User') }} @@ -599,7 +599,7 @@ export default { if (contactIndex === -1) { showError( this.t( - 'softwarecatalog', + 'stackiq', 'Contactpersoon not found in organisation data', ), ) @@ -612,12 +612,7 @@ export default { contactObject.loading = true } else { console.error('Contactpersoon is not an object:', contactObject) - showError( - this.t( - 'softwarecatalog', - 'Invalid contact person data structure', - ), - ) + showError(this.t('stackiq', 'Invalid contact person data structure')) return } @@ -672,19 +667,13 @@ export default { console.info('Refreshing user info after successful conversion...') await this.refreshUserData() - showSuccess( - this.t('softwarecatalog', 'User account created successfully'), - ) + showSuccess(this.t('stackiq', 'User account created successfully')) } catch (error) { console.error('Error in convertToUser:', error) showError( - this.t( - 'softwarecatalog', - 'Failed to create user account: {error}', - { - error: error.message, - }, - ), + this.t('stackiq', 'Failed to create user account: {error}', { + error: error.message, + }), ) // Clear loading state on error - ensure it's an object first @@ -777,13 +766,13 @@ export default { async disableUser(contactpersoon) { try { await this.organisatieStore.disableUser(contactpersoon.id) - showSuccess(this.t('softwarecatalog', 'User disabled successfully')) + showSuccess(this.t('stackiq', 'User disabled successfully')) // Update the local contactpersoon data to reflect disabled status this.updateContactpersoonStatus(contactpersoon.id, true) } catch (error) { showError( - this.t('softwarecatalog', 'Failed to disable user: {error}', { + this.t('stackiq', 'Failed to disable user: {error}', { error: error.message, }), ) @@ -799,13 +788,13 @@ export default { async enableUser(contactpersoon) { try { await this.organisatieStore.enableUser(contactpersoon.id) - showSuccess(this.t('softwarecatalog', 'User enabled successfully')) + showSuccess(this.t('stackiq', 'User enabled successfully')) // Update the local contactpersoon data to reflect enabled status this.updateContactpersoonStatus(contactpersoon.id, false) } catch (error) { showError( - this.t('softwarecatalog', 'Failed to enable user: {error}', { + this.t('stackiq', 'Failed to enable user: {error}', { error: error.message, }), ) diff --git a/src/components/PaginationComponent.vue b/src/components/PaginationComponent.vue index a63bc924..c07b0f07 100644 --- a/src/components/PaginationComponent.vue +++ b/src/components/PaginationComponent.vue @@ -4,7 +4,7 @@
{{ - t('softwarecatalog', 'Page {current} of {total}', { + t('stackiq', 'Page {current} of {total}', { current: currentPage, total: totalPages, }) @@ -16,14 +16,14 @@
- {{ t('softwarecatalog', 'First') }} + {{ t('stackiq', 'First') }} - {{ t('softwarecatalog', 'Previous') }} + {{ t('stackiq', 'Previous') }} @@ -50,29 +50,27 @@ - {{ t('softwarecatalog', 'Next') }} + {{ t('stackiq', 'Next') }} - {{ t('softwarecatalog', 'Last') }} + {{ t('stackiq', 'Last') }}
- +
diff --git a/src/components/cards/OrganisatieCard.vue b/src/components/cards/OrganisatieCard.vue index 9dd9a61a..f5360c3c 100644 --- a/src/components/cards/OrganisatieCard.vue +++ b/src/components/cards/OrganisatieCard.vue @@ -1,8 +1,7 @@ /** * OrganisatieCard.vue * Custom card component for displaying organisatie objects -* @category Components * @package softwarecatalog * @author Ruben Linde * @copyright -2024 * @license EUPL-1.2 -https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * @version 1.0.0 * -@link https://github.com/opencatalogi/softwarecatalog */ +* @category Components * @package stackiq * @author Ruben Linde * @copyright 2024 * +@license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * +@version 1.0.0 * @link https://github.com/ConductionNL/stackiq */ - {{ t('softwarecatalog', 'Preview merge') }} + {{ t('stackiq', 'Preview merge') }} @@ -254,15 +246,13 @@ export default { const obj = data && data['@self'] !== undefined ? data : data.object || data this.sourceName = - obj.name - || obj.name - || t('softwarecatalog', 'Unknown organisation') + obj.name || obj.name || t('stackiq', 'Unknown organisation') this.status = obj.status || '' this.mergedInto = obj.mergedInto || '' } catch (e) { // Non-fatal — the panel still renders merge controls with an // empty source name rather than failing the whole detail page. - this.sourceName = t('softwarecatalog', 'Unknown organisation') + this.sourceName = t('stackiq', 'Unknown organisation') } finally { this.loading = false } @@ -310,10 +300,7 @@ export default { || String(org.id), })) } catch (e) { - this.error = t( - 'softwarecatalog', - 'Could not load target organisations.', - ) + this.error = t('stackiq', 'Could not load target organisations.') } finally { this.loadingTargets = false } @@ -347,7 +334,7 @@ export default { this.showConfirm = true } catch (e) { this.error = - e.message || t('softwarecatalog', 'Could not preview the merge.') + e.message || t('stackiq', 'Could not preview the merge.') } finally { this.previewing = false } @@ -374,13 +361,10 @@ export default { this.success = true this.status = 'merged' this.mergedInto = String(this.selectedTarget.value) - showSuccess( - t('softwarecatalog', 'Organisation successfully merged.'), - ) + showSuccess(t('stackiq', 'Organisation successfully merged.')) } catch (e) { this.confirmError = - e.message - || t('softwarecatalog', 'Could not merge the organisations.') + e.message || t('stackiq', 'Could not merge the organisations.') } finally { this.busy = false } diff --git a/src/components/organisations/OrganisationSwitcher.vue b/src/components/organisations/OrganisationSwitcher.vue index 2e8cd988..1c3a21ea 100644 --- a/src/components/organisations/OrganisationSwitcher.vue +++ b/src/components/organisations/OrganisationSwitcher.vue @@ -51,7 +51,7 @@ - {{ t('softwarecatalog', 'Manage members') }} + {{ t('stackiq', 'Manage members') }} - SPDX-License-Identifier: EUPL-1.2 - - - Ratings & reviews body widget (softwarecatalog#375) — registered via + - Ratings & reviews body widget (stackiq#375) — registered via - src/customComponents.js and placed on ModuleDetail's `bodyWidgets` - (same escape hatch as ContractApprovalPanel/OrganisationMergePanel). - Shows the approved-only aggregate (average + count) computed server-side @@ -17,7 +17,7 @@