Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added __pycache__/compare_archimate.cpython-38.pyc
Binary file not shown.
436 changes: 436 additions & 0 deletions compare_archimate.py

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@
use OCA\SoftwareCatalog\EventListener\SoftwareCatalogEventListener;
use OCA\SoftwareCatalog\EventListener\TestEventListener;
use OCA\SoftwareCatalog\EventListener\ModuleComplianceSubscriber;
use OCA\SoftwareCatalog\EventListener\UserProfileUpdatedEventListener;

use OCA\OpenRegister\Event\ObjectCreatedEvent;
use OCA\OpenRegister\Event\ObjectUpdatedEvent;
use OCA\OpenRegister\Event\ObjectDeletedEvent;
use OCA\OpenRegister\Event\ObjectLockedEvent;
use OCA\OpenRegister\Event\ObjectUnlockedEvent;
use OCA\OpenRegister\Event\ObjectRevertedEvent;
use OCA\OpenRegister\Event\UserProfileUpdatedEvent;
use OCA\OpenRegister\Event\OrganisationCreatedEvent;
use OCA\OpenRegister\Event\RegisterCreatedEvent;
use OCA\OpenRegister\Event\RegisterDeletedEvent;
Expand Down Expand Up @@ -150,6 +152,9 @@ public function register(IRegistrationContext $context): void
$context->registerEventListener(ObjectCreatedEvent::class, ModuleComplianceSubscriber::class);
$context->registerEventListener(ObjectUpdatedEvent::class, ModuleComplianceSubscriber::class);

// Register listener to sync user profile updates to contactpersoon objects
$context->registerEventListener(UserProfileUpdatedEvent::class, UserProfileUpdatedEventListener::class);



// Organization event listeners removed - now using cron job for organization synchronization
Expand Down
12 changes: 10 additions & 2 deletions lib/Controller/ContactpersonenController.php
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,16 @@ public function changePassword(string $username, string $newPassword): JSONRespo
], 400);
}

// Set new password
$user->setPassword($newPassword);
// Set new password — setPassword() returns false if the password
// is rejected (e.g., compromised password list, policy violation).
$result = $user->setPassword($newPassword);

if ($result === false) {
return new JSONResponse([
'success' => false,
'message' => 'Password was rejected. It may be too common or violate the password policy. Please choose a different password.'
], 400);
}

$this->logger->info('Password changed for user', [
'username' => $username
Expand Down
16 changes: 15 additions & 1 deletion lib/EventListener/ModuleComplianceSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
namespace OCA\SoftwareCatalog\EventListener;

use OCA\SoftwareCatalog\Service\ModuleComplianceService;
use OCA\SoftwareCatalog\Service\ModuleVersionService;
use OCA\SoftwareCatalog\Service\SettingsService;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
Expand Down Expand Up @@ -109,7 +110,7 @@ public function handle(Event $event): void
// Handle module compliance update
$moduleComplianceService = $this->container->get(ModuleComplianceService::class);
$moduleComplianceService->handleModuleComplianceUpdate($object);

$logger->info('ModuleComplianceSubscriber: Successfully processed module compliance update', [
'objectId' => $objectId,
'timestamp' => date('Y-m-d H:i:s')
Expand All @@ -123,5 +124,18 @@ public function handle(Event $event): void
'trace' => $e->getTraceAsString()
]);
}

// Ensure the module has at least one version (default 1.0.0).
try {
$moduleVersionService = $this->container->get(ModuleVersionService::class);
$moduleVersionService->ensureDefaultVersion($object);
} catch (\Exception $e) {
$logger->error('ModuleComplianceSubscriber: Failed to ensure default module version', [
'objectId' => $objectId,
'exception' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
}
}
}
196 changes: 196 additions & 0 deletions lib/EventListener/UserProfileUpdatedEventListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
<?php

/**
* UserProfileUpdatedEvent Listener
*
* Listens for user profile updates from OpenRegister and syncs
* the changed fields back to the corresponding contactpersoon object.
*
* @category EventListener
* @package OCA\SoftwareCatalog\EventListener
* @author Conduction b.v. <info@conduction.nl>
* @copyright 2024 Conduction B.V.
* @license AGPL-3.0-or-later https://www.gnu.org/licenses/agpl-3.0.html
*/

declare(strict_types=1);

namespace OCA\SoftwareCatalog\EventListener;

use OCA\OpenRegister\Event\UserProfileUpdatedEvent;
use OCA\SoftwareCatalog\Service\SettingsService;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use Psr\Log\LoggerInterface;

/**
* Syncs user profile changes to the corresponding contactpersoon object.
*
* When a user updates their profile via /api/user/me, this listener finds
* the matching contactpersoon (by username field) and updates the relevant
* fields: voornaam, tussenvoegsel, achternaam, functie, e-mailadres.
*
* @implements IEventListener<UserProfileUpdatedEvent>
*/
class UserProfileUpdatedEventListener implements IEventListener
{
/**
* Field mapping from user profile keys to contactpersoon keys.
*/
private const FIELD_MAP = [
'firstName' => 'voornaam',
'middleName' => 'tussenvoegsel',
'lastName' => 'achternaam',
'functie' => 'functie',
'email' => 'e-mailadres',
];

public function __construct()
{
}

/**
* Handle the UserProfileUpdatedEvent.
*
* @param Event $event The dispatched event.
*
* @return void
*/
public function handle(Event $event): void
{
if ($event instanceof UserProfileUpdatedEvent === false) {
return;
}

try {
$logger = \OC::$server->get(LoggerInterface::class);
$changes = $event->getChanges();

// Check if any of the mapped fields were changed.
$relevantChanges = array_intersect($changes, array_keys(self::FIELD_MAP));
if (empty($relevantChanges) === true) {
$logger->debug('[UserProfileUpdatedEventListener] No relevant field changes for contactpersoon sync', [
'userId' => $event->getUserId(),
'changes' => $changes,
]);
return;
}

$logger->info('[UserProfileUpdatedEventListener] Syncing user profile changes to contactpersoon', [
'userId' => $event->getUserId(),
'relevantChanges' => $relevantChanges,
]);

$this->syncToContactpersoon($event, $logger);
} catch (\Exception $e) {
try {
$logger = \OC::$server->get(LoggerInterface::class);
$logger->error('[UserProfileUpdatedEventListener] Error syncing profile to contactpersoon', [
'userId' => $event->getUserId(),
'exception' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
} catch (\Exception $logException) {
// Silently fail if logging fails.
}
}
}

/**
* Find the contactpersoon object by username and update its fields.
*
* @param UserProfileUpdatedEvent $event The profile updated event.
* @param LoggerInterface $logger The logger.
*
* @return void
*/
private function syncToContactpersoon(UserProfileUpdatedEvent $event, LoggerInterface $logger): void
{
$objectService = \OC::$server->get('OCA\OpenRegister\Service\ObjectService');
$settingsService = \OC::$server->get(SettingsService::class);

// Get the voorzieningen config for register and schema.
$voorzieningenConfig = $settingsService->getVoorzieningenConfig();
$register = $voorzieningenConfig['register'] ?? '';
$contactpersoonSchema = $voorzieningenConfig['contactpersoon_schema'] ?? '';

if (empty($register) === true || empty($contactpersoonSchema) === true) {
$logger->warning('[UserProfileUpdatedEventListener] Voorzieningen config missing register or contactpersoon_schema');
return;
}

$userId = $event->getUserId();

// Find contactpersoon by username field using searchObjects.
$query = [
'@self' => [
'register' => (int) $register,
'schema' => (int) $contactpersoonSchema,
],
'username' => $userId,
];

$results = $objectService->searchObjects(
query: $query,
_rbac: false,
_multitenancy: false
);

if (empty($results) === true || (is_array($results) === true && count($results) === 0)) {
$logger->info('[UserProfileUpdatedEventListener] No contactpersoon found for user', [
'userId' => $userId,
'register' => $register,
'schema' => $contactpersoonSchema,
]);
return;
}

// Get the first matching contactpersoon.
$contactpersoon = is_array($results) === true ? reset($results) : $results;
$contactData = $contactpersoon->getObject();
$newData = $event->getNewData();
$changes = $event->getChanges();

// Build the patch with only changed fields.
$patch = [];
foreach (self::FIELD_MAP as $userField => $contactField) {
if (in_array($userField, $changes, true) === false) {
continue;
}

$newValue = $newData[$userField] ?? null;
$patch[$contactField] = $newValue ?? '';
}

if (empty($patch) === true) {
$logger->debug('[UserProfileUpdatedEventListener] No fields to patch on contactpersoon', [
'userId' => $userId,
]);
return;
}

$logger->info('[UserProfileUpdatedEventListener] Patching contactpersoon object', [
'userId' => $userId,
'contactpersoonId' => $contactpersoon->getUuid(),
'patch' => $patch,
]);

// Only save the changed fields to avoid property authorization issues
// with protected fields like 'rollen'.
$objectService->saveObject(
register: $contactpersoon->getRegister(),
schema: $contactpersoon->getSchema(),
object: $patch,
_rbac: false,
_multitenancy: false,
uuid: $contactpersoon->getUuid()
);

$logger->info('[UserProfileUpdatedEventListener] Successfully synced user profile to contactpersoon', [
'userId' => $userId,
'contactpersoonId' => $contactpersoon->getUuid(),
'patchedFields' => array_keys($patch),
]);
}
}
Loading
Loading