diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..0931299 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,55 @@ +# Space Profiles Installation Guide + +This guide installs the `space_profiles` module in a reusable way for any HumHub instance. + +## 1. Requirements + +- HumHub `1.14+` +- Module directory access on the target instance +- Optional but recommended: `rescue_foundation` module + +## 2. Clone into HumHub Modules Directory + +The folder name must be exactly `space_profiles`. + +```bash +git clone https://gitea.kelinreij.duckdns.org/humhub-modules/space-profiles.git \ + /var/www/localhost/htdocs/protected/modules/space_profiles +``` + +If the folder already exists: + +```bash +cd /var/www/localhost/htdocs/protected/modules/space_profiles +git pull +``` + +## 3. Enable the Module + +In HumHub UI: + +1. Go to `Administration` -> `Modules`. +2. Enable `Space Profiles`. +3. Enable it per space where needed. + +## 4. Run Migrations + +From the HumHub app host/container: + +```bash +php /var/www/localhost/htdocs/protected/yii migrate/up \ + --include-module-migrations=1 --interactive=0 +``` + +## 5. Verify + +1. Open a space with module enabled. +2. Confirm profile page renders the template sections. +3. Confirm space settings page saves expected profile fields. + +## Docker Example + +```bash +docker exec humhub php /var/www/localhost/htdocs/protected/yii migrate/up \ + --include-module-migrations=1 --interactive=0 +``` diff --git a/controllers/SettingsController.php b/controllers/SettingsController.php index 99d7218..cff9c66 100644 --- a/controllers/SettingsController.php +++ b/controllers/SettingsController.php @@ -7,8 +7,10 @@ use humhub\modules\content\components\ContentContainerControllerAccess; use humhub\modules\rescue_foundation\widgets\RescueSettingsMenu; use humhub\modules\space\models\Space; use humhub\modules\space_profiles\models\forms\SpaceProfileForm; +use humhub\modules\space_profiles\services\ModuleSetupService; use Yii; use yii\web\UploadedFile; +use yii\web\BadRequestHttpException; class SettingsController extends ContentContainerController { @@ -41,4 +43,34 @@ class SettingsController extends ContentContainerController 'subNav' => $subNav, ]); } + + public function actionSetup() + { + if (!Yii::$app->request->isPost) { + throw new BadRequestHttpException('Invalid request method.'); + } + + if (!$this->contentContainer instanceof Space) { + $this->view->error(Yii::t('SpaceProfilesModule.base', 'Setup can only be run inside a space.')); + return $this->redirect($this->contentContainer->createUrl('/space_profiles/settings')); + } + + try { + $result = ModuleSetupService::runForSpace($this->contentContainer); + $appliedCount = count($result['applied'] ?? []); + + if ($appliedCount > 0) { + $this->view->success(Yii::t('SpaceProfilesModule.base', 'Setup completed. Applied {count} migration(s).', [ + 'count' => $appliedCount, + ])); + } else { + $this->view->success(Yii::t('SpaceProfilesModule.base', 'Setup completed. No pending migrations were found.')); + } + } catch (\Throwable $e) { + Yii::error($e, 'space_profiles.setup'); + $this->view->error(Yii::t('SpaceProfilesModule.base', 'Setup failed. Please check logs and try again.')); + } + + return $this->redirect($this->contentContainer->createUrl('/space_profiles/settings')); + } } diff --git a/services/ModuleSetupService.php b/services/ModuleSetupService.php new file mode 100644 index 0000000..e4c5945 --- /dev/null +++ b/services/ModuleSetupService.php @@ -0,0 +1,70 @@ +createUrl('/space_profiles/profile/view'); + $settings = $space->getSettings(); + $settings->set('indexUrl', $defaultUrl); + $settings->set('indexGuestUrl', $defaultUrl); + + $result['defaultHomeUrl'] = $defaultUrl; + return $result; + } + + private static function applyModuleMigrations(): array + { + $migrationDir = dirname(__DIR__) . '/migrations'; + $files = glob($migrationDir . '/m*.php') ?: []; + sort($files, SORT_NATURAL); + + $existingVersions = Yii::$app->db->createCommand('SELECT version FROM migration')->queryColumn(); + $history = array_fill_keys($existingVersions, true); + + $applied = []; + $skipped = []; + + foreach ($files as $file) { + $version = pathinfo($file, PATHINFO_FILENAME); + if (isset($history[$version])) { + $skipped[] = $version; + continue; + } + + if (!class_exists($version, false)) { + require_once $file; + } + + if (!class_exists($version, false)) { + throw new \RuntimeException('Migration class not found: ' . $version); + } + + $migration = new $version(); + $ok = method_exists($migration, 'safeUp') ? $migration->safeUp() : $migration->up(); + if ($ok === false) { + throw new \RuntimeException('Migration failed: ' . $version); + } + + Yii::$app->db->createCommand()->insert('migration', [ + 'version' => $version, + 'apply_time' => time(), + ])->execute(); + + $applied[] = $version; + $history[$version] = true; + } + + return [ + 'applied' => $applied, + 'skipped' => $skipped, + ]; + } +} diff --git a/views/profile/_rescue-info.php b/views/profile/_rescue-info.php new file mode 100644 index 0000000..c06e724 --- /dev/null +++ b/views/profile/_rescue-info.php @@ -0,0 +1,52 @@ + + +
+
+ +
+ +
+ +
+ name) ?> +
+
address) ?>
+
city) ?>, state) ?> zip) ?>
+
+ : + email) ?> +
+
+ : + phone) ?> +
+ + mission_statement) !== '' || trim((string)$profile->animals_we_accept) !== ''): ?> +
+ + + +
+ + + mission_statement) !== ''): ?> +
:
+
mission_statement)) ?>
+ + + animals_we_accept) !== ''): ?> +
:
+
animals_we_accept)) ?>
+ + +
+
diff --git a/views/profile/templates/rescue-center.php b/views/profile/templates/rescue-center.php index 461fd57..69c21b4 100644 --- a/views/profile/templates/rescue-center.php +++ b/views/profile/templates/rescue-center.php @@ -4,7 +4,6 @@ use yii\helpers\Html; /* @var \humhub\modules\space\models\Space $space */ /* @var \humhub\modules\space_profiles\models\SpaceProfile $profile */ -/* @var string $searchBlockWidget */ ?>
@@ -30,16 +29,6 @@ use yii\helpers\Html;
body_html ?>
-
- - $space]) ?> - -
- -
- -
- footer_html)): ?>
footer_html ?>
diff --git a/views/profile/view.php b/views/profile/view.php index 5670fe8..c90f448 100644 --- a/views/profile/view.php +++ b/views/profile/view.php @@ -1,8 +1,11 @@ background_image_path)) { $searchBlockWidget = '\\humhub\\modules\\animal_management\\widgets\\SearchAnimalProfilesBlock'; $templateView = TemplateRegistry::resolveView($profile ? $profile->template_key : null); -$spaceDescription = trim((string)$space->about); -if ($spaceDescription === '') { - $spaceDescription = trim((string)$space->description); -} - -if ($spaceDescription === '') { - $spaceDescription = trim((string)($profile?->description ?? '')); -} ?>
@@ -42,52 +37,58 @@ if ($spaceDescription === '') { render($templateView, [ 'space' => $space, 'profile' => $profile, - 'searchBlockWidget' => $searchBlockWidget, ]) ?>
beginBlock('sidebar'); ?> -
-
- -
- -
- -
- name) ?> -
-
address) ?>
-
city) ?>, state) ?> zip) ?>
-
- : - email) ?> -
-
- : - phone) ?> -
+mission_statement) !== '' || trim((string)$profile->animals_we_accept) !== ''): ?> -
- +if ($profile && class_exists($searchBlockWidget)) { + $sidebarWidgets[] = [$searchBlockWidget, ['contentContainer' => $space], ['sortOrder' => 20]]; +} - -
- - - mission_statement) !== ''): ?> -
:
-
mission_statement)) ?>
- - - animals_we_accept) !== ''): ?> -
:
-
animals_we_accept)) ?>
- - -
-
+echo SpaceSidebar::widget([ + 'space' => $space, + 'widgets' => $sidebarWidgets, +]); +?> endBlock(); ?> + + + + registerJs(<< + diff --git a/views/settings/index.php b/views/settings/index.php index 60cfd48..31ede95 100644 --- a/views/settings/index.php +++ b/views/settings/index.php @@ -20,6 +20,25 @@ $profile = $model->getProfile();
+
+
+
+ +
+
+ +
+ contentContainer->createUrl('/space_profiles/settings/setup'), + [ + 'class' => 'btn btn-primary btn-sm', + 'data-method' => 'post', + 'data-confirm' => Yii::t('SpaceProfilesModule.base', 'Run Space Profiles setup now for this space?'), + ] + ) ?> +
+
diff --git a/widgets/RescueInfoSidebar.php b/widgets/RescueInfoSidebar.php new file mode 100644 index 0000000..7471ffb --- /dev/null +++ b/widgets/RescueInfoSidebar.php @@ -0,0 +1,31 @@ + $this->space->contentcontainer_id]); + + $spaceDescription = trim((string)$this->space->about); + if ($spaceDescription === '') { + $spaceDescription = trim((string)$this->space->description); + } + if ($spaceDescription === '') { + $spaceDescription = trim((string)($profile?->description ?? '')); + } + + return $this->render('rescueInfoSidebar', [ + 'space' => $this->space, + 'profile' => $profile, + 'spaceDescription' => $spaceDescription, + ]); + } +} diff --git a/widgets/views/rescueInfoSidebar.php b/widgets/views/rescueInfoSidebar.php new file mode 100644 index 0000000..c06e724 --- /dev/null +++ b/widgets/views/rescueInfoSidebar.php @@ -0,0 +1,52 @@ + + +
+
+ +
+ +
+ +
+ name) ?> +
+
address) ?>
+
city) ?>, state) ?> zip) ?>
+
+ : + email) ?> +
+
+ : + phone) ?> +
+ + mission_statement) !== '' || trim((string)$profile->animals_we_accept) !== ''): ?> +
+ + + +
+ + + mission_statement) !== ''): ?> +
:
+
mission_statement)) ?>
+ + + animals_we_accept) !== ''): ?> +
:
+
animals_we_accept)) ?>
+ + +
+