From f4dc336c88fd19a27171ac034e724f678dcc8b58 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Tue, 2 Jun 2026 20:54:08 +0200 Subject: [PATCH] Club System --- Api/Controller/EntryController.php | 25 +++++++ ApprovalQueue/ClubRequest.php | 83 +++++++++++++++++++++++ Entity/ClubRequest.php | 75 ++++++++++++++++++++ Pub/Controller/Club.php | 32 +++++++++ Pub/Controller/Webhook.php | 36 ---------- Setup.php | 23 +++++++ XF/Entity/User.php | 18 +++++ _output/navigation/_metadata.json | 4 +- _output/navigation/contact_us.json | 2 +- _output/navigation/submissions_queue.json | 2 +- _output/permissions/_metadata.json | 24 +++++++ _output/phrases/_metadata.json | 72 ++++++++++++++++++++ _output/templates/_metadata.json | 15 ++++ 13 files changed, 371 insertions(+), 40 deletions(-) create mode 100644 Api/Controller/EntryController.php create mode 100644 ApprovalQueue/ClubRequest.php create mode 100644 Entity/ClubRequest.php create mode 100644 Pub/Controller/Club.php delete mode 100644 Pub/Controller/Webhook.php create mode 100644 XF/Entity/User.php diff --git a/Api/Controller/EntryController.php b/Api/Controller/EntryController.php new file mode 100644 index 0000000..1b60457 --- /dev/null +++ b/Api/Controller/EntryController.php @@ -0,0 +1,25 @@ +filter('user_id', 'uint'); + $count = $this->filter('count', 'uint'); + + $user = $this->assertRecordExists('XF:User', $userId); + + $user->rhpz_entry_count = $count; + $user->save(); + + $trophyRepo = $this->repository('XF:Trophy'); + $trophyRepo->updateTrophiesForUser($user); + + return $this->apiSuccess(['success' => true,'user_id' => $user->user_id,'count' => $count]); + } +} \ No newline at end of file diff --git a/ApprovalQueue/ClubRequest.php b/ApprovalQueue/ClubRequest.php new file mode 100644 index 0000000..97c7d2b --- /dev/null +++ b/ApprovalQueue/ClubRequest.php @@ -0,0 +1,83 @@ +canActionContent($content, $error); + } + + protected function canActionContent(Entity $content, &$error = null) + { + return \XF::visitor()->hasAdminPermission('node'); + } + + public function getEntityWith() + { + return ['User']; + } + + public function actionApprove(\RomhackPlaza\Master\Entity\ClubRequest $clubRequest) + { + $clubRequest->request_state = 'visible'; + $clubRequest->save(); + + $node = \XF::em()->create('XF:Node'); + $node->node_type_id = 'Forum'; + $node->title = $clubRequest->title; + $node->description = $clubRequest->description; + $node->parent_node_id = \XF::options()->rhpz_club_node_id ?? 0; + $node->display_order = 1; + $node->save(); + + $forum = \XF::em()->create('XF:Forum'); + $forum->node_id = $node->node_id; + $forum->allow_posting = true; + $forum->save(); + + $user = $clubRequest->User; + if ($user) { + + $modContent = \XF::em()->create('XF:ModeratorContent'); + $modContent->content_type = 'node'; + $modContent->content_id = $node->node_id; + $modContent->user_id = $user->user_id; + $modContent->save(); + + $permissionUpdater = \XF::app()->service('XF:UpdatePermissions'); + $permissionUpdater->setContent('node', $node->node_id); + $permissionUpdater->setUser($user); + + $permissionUpdater->updatePermissions([ + 'forum' => [ + 'editAnyPost' => 'content_allow', + 'deleteAnyPost' => 'content_allow', + 'deleteAnyThread' => 'content_allow', + 'inlineMod' => 'content_allow', + 'lockUnlockThread' => 'content_allow', + 'stickUnstickThread' => 'content_allow' + ] + ]); + + // D. Reconstruction des permissions + \XF::app()->jobManager()->enqueueUnique('permissionRebuild', 'XF:PermissionRebuild'); + } + } + + public function actionReject(\RomhackPlaza\Master\Entity\ClubRequest $clubRequest) + { + $clubRequest->request_state = 'rejected'; + $clubRequest->save(); + } + + public function getTemplateName() + { + return 'public:approval_item_club_request'; + } +} \ No newline at end of file diff --git a/Entity/ClubRequest.php b/Entity/ClubRequest.php new file mode 100644 index 0000000..c0754b0 --- /dev/null +++ b/Entity/ClubRequest.php @@ -0,0 +1,75 @@ +table = 'xf_club_request'; + $structure->shortName = 'RomhackPlaza\Master:ClubRequest'; + $structure->primaryKey = 'request_id'; + $structure->columns = [ + 'request_id' => ['type' => self::UINT, 'autoIncrement' => true], + 'user_id' => ['type' => self::UINT, 'required' => true], + 'title' => ['type' => self::STR, 'maxLength' => 100, 'required' => true], + 'description' => ['type' => self::STR, 'required' => true], + 'request_state' => ['type' => self::STR, 'default' => 'moderated', + 'allowedValues' => ['visible', 'moderated', 'rejected'] + ], + 'request_date' => ['type' => self::UINT, 'default' => \XF::$time] + ]; + $structure->relations = [ + 'User' => [ + 'entity' => 'XF:User', + 'type' => self::TO_ONE, + 'conditions' => 'user_id', + 'primary' => true + ] + ]; + + return $structure; + } + + protected function _postSave() + { + if( $this->isInsert() && $this->request_state == 'moderated' ){ + $this->inQueue(); + } else if( $this->isUpdate() && $this->isChanged('request_state') ){ + if( $this->request_state === 'moderated' ){ + $this->inQueue(); + } else { + $this->removeQueue(); + } + } + } + + protected function _postDelete() + { + if( $this->request_state === 'moderated' ){ + $this->removeQueue(); + } + } + + protected function inQueue() + { + $queue = $this->em()->find('XF:ApprovalQueue', ['club_request', $this->request_id ] ); + if( !$queue ) + { + $newQueue = $this->em()->create('XF:ApprovalQueue'); + $newQueue->content_type = 'club_request'; + $newQueue->content_id = $this->request_id; + $newQueue->save(); + } + } + + protected function removeQueue() + { + $queue = $this->em()->find('XF:ApprovalQueue', ['club_request', $this->request_id ] ); + if( $queue ) + $queue->delete(); + } +} \ No newline at end of file diff --git a/Pub/Controller/Club.php b/Pub/Controller/Club.php new file mode 100644 index 0000000..747c2c3 --- /dev/null +++ b/Pub/Controller/Club.php @@ -0,0 +1,32 @@ +assertRegistrationRequired(); + + return $this->view('RomhackPlaza\Master:Club\Request', 'club_request_form'); + } + + public function actionSave(ParameterBag $params) + { + $this->assertRegistrationRequired(); + $this->assertPostOnly(); + + $entity = $this->em()->create('RomhackPlaza\Master:ClubRequest'); + $entity->user_id = \XF::visitor()->user_id; + $entity->title = $this->filter('title','str'); + $entity->description = $this->filter('description','str'); + $entity->request_state = 'moderated'; + $entity->save(); + + return $this->redirect($this->buildLink('clubs'), "Your club creation request has been submitted and is awaiting approval by a staff member."); + } +} \ No newline at end of file diff --git a/Pub/Controller/Webhook.php b/Pub/Controller/Webhook.php deleted file mode 100644 index 016968d..0000000 --- a/Pub/Controller/Webhook.php +++ /dev/null @@ -1,36 +0,0 @@ -assertPostOnly(); - - $token = $this->filter('_token', 'str'); - $secret = \XF::options()->rhpz_webhook_secret ?? ''; - - if( !$secret || !hash_equals($secret, $token) ){ - return $this->error('Unauthorized', 401); - } - - $userId = $this->filter('user_id', 'uint'); - $count = $this->filter('count', 'uint'); - - $user = \XF::em()->find('XF:User', $userId); - if( !$user ){ - return $this->error('User not found', 404); - } - - $user->rhpz_entry_count = $count; - $user->save(); - - $trophyService = \XF::service('XF:Trophy\Notify', $user); - $trophyService->checkAndAwardTrophies(); - - return $this->apiSuccess(['count' => $count]); - } -} \ No newline at end of file diff --git a/Setup.php b/Setup.php index 3401385..83d1c76 100644 --- a/Setup.php +++ b/Setup.php @@ -6,6 +6,7 @@ use XF\AddOn\AbstractSetup; use XF\AddOn\StepRunnerInstallTrait; use XF\AddOn\StepRunnerUninstallTrait; use XF\AddOn\StepRunnerUpgradeTrait; +use XF\Db\Schema\Create; class Setup extends AbstractSetup { @@ -23,10 +24,32 @@ class Setup extends AbstractSetup }); } + /** + * Create club request table. + * @return void + */ + public function installStep2(): void + { + $this->schemaManager()->createTable('xf_club_request', function(Create $table){ + $table->addColumn('request_id', 'int')->autoIncrement(); + $table->addColumn('user_id', 'int'); + $table->addColumn('title', 'varchar', 100); + $table->addColumn('description', 'text'); + $table->addColumn('request_state', 'enum')->values(['visible','moderated','rejected'])->setDefault('moderated'); + $table->addColumn('request_date','int'); + $table->addKey('request_state'); + }); + } + public function uninstallStep1(): void { $this->schemaManager()->alterTable('xf_user', function($table) { $table->dropColumns(['rhpz_entry_count']); }); } + + public function uninstallStep2(): void + { + $this->schemaManager()->dropTable('xf_club_request'); + } } \ No newline at end of file diff --git a/XF/Entity/User.php b/XF/Entity/User.php new file mode 100644 index 0000000..4037bc6 --- /dev/null +++ b/XF/Entity/User.php @@ -0,0 +1,18 @@ +columns['rhpz_entry_count'] = [ 'type' => self::UINT, 'default' => 0 ]; + + return $structure; + } +} \ No newline at end of file diff --git a/_output/navigation/_metadata.json b/_output/navigation/_metadata.json index f0dcf00..b8b2f6d 100644 --- a/_output/navigation/_metadata.json +++ b/_output/navigation/_metadata.json @@ -6,7 +6,7 @@ "hash": "bddec05ee1acb9cb82ed72155bdd7817" }, "contact_us.json": { - "hash": "2a0528c2bc4338d4541074f90790c127" + "hash": "05d205aee6ac1db9d9ad0f68bdd4f7c2" }, "database.json": { "hash": "7b42b608fad8ab23417a8cc3fcd331c2" @@ -42,7 +42,7 @@ "hash": "73fab3932646c350da9a40102f650d9d" }, "submissions_queue.json": { - "hash": "f603ca2b1de0c4aaf60fadcec9ea85a7" + "hash": "84060a775af4419d44c8dc2c083ef447" }, "tools.json": { "hash": "0221bb27d36511c5dd1feaf697626778" diff --git a/_output/navigation/contact_us.json b/_output/navigation/contact_us.json index 4835439..1fcb8d4 100644 --- a/_output/navigation/contact_us.json +++ b/_output/navigation/contact_us.json @@ -3,7 +3,7 @@ "display_order": 3, "navigation_type_id": "basic", "type_config": { - "link": "{$xf.options.homePageUrl}/pages/contact-us", + "link": "{{ link('misc/contact') }}", "display_condition": "", "extra_attributes": { "icon": "at-sign" diff --git a/_output/navigation/submissions_queue.json b/_output/navigation/submissions_queue.json index 77a24c8..9439978 100644 --- a/_output/navigation/submissions_queue.json +++ b/_output/navigation/submissions_queue.json @@ -3,7 +3,7 @@ "display_order": 3, "navigation_type_id": "basic", "type_config": { - "link": "{$xf.options.homePageUrl}/submissions-queue", + "link": "{$xf.options.homePageUrl}/queue", "display_condition": "", "extra_attributes": { "icon": "gavel" diff --git a/_output/permissions/_metadata.json b/_output/permissions/_metadata.json index db36751..b22d231 100644 --- a/_output/permissions/_metadata.json +++ b/_output/permissions/_metadata.json @@ -1,7 +1,31 @@ { + "romhackplaza-canEditMyEntries.json": { + "hash": "4fa023f096147e72d0ca94e5ce231228" + }, + "romhackplaza-canEditOthersEntries.json": { + "hash": "c2e1c6213b7266fa56ead62676784a26" + }, + "romhackplaza-canModerateEntries.json": { + "hash": "dfee0d9b78d1833c648d9c5047c29a33" + }, + "romhackplaza-canSeeHiddenEntries.json": { + "hash": "3a71377fae8f064eafaef3ac0f8bed68" + }, + "romhackplaza-canSeeLockedEntries.json": { + "hash": "f0907b5c0da0c465195a19babd671343" + }, + "romhackplaza-canSeeOthersDrafts.json": { + "hash": "fbd94dac811e001e8923ed28da460367" + }, + "romhackplaza-canSeeRejectedEntries.json": { + "hash": "5c015bf4b7012720a4f7bcfdb8eb9521" + }, "romhackplaza-canSubmitEntry.json": { "hash": "6eeb397b6596b6774af70dbbf5454106" }, + "romhackplaza-canSubmitEntryInPublished.json": { + "hash": "39acd4f2cc864663e5978b18cb390a5c" + }, "romhackplaza-canSubmitTempFile.json": { "hash": "d514bba0211dc91897efce276c499131" }, diff --git a/_output/phrases/_metadata.json b/_output/phrases/_metadata.json index 490fb85..7135574 100644 --- a/_output/phrases/_metadata.json +++ b/_output/phrases/_metadata.json @@ -101,12 +101,84 @@ "version_string": "1.0.0", "hash": "15bbb9d0bbf25e8d2978de1168c749dc" }, + "option.rhpz_club_node_id.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "e73496f262c162a1a35bd9e990b36825" + }, + "option_explain.rhpz_club_node_id.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "d41d8cd98f00b204e9800998ecf8427e" + }, + "option_group.romhackplaza.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "4b206b2374c877bad80e7cd2303936be" + }, + "option_group_description.romhackplaza.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "d41d8cd98f00b204e9800998ecf8427e" + }, + "permission.romhackplaza_canEditMyEntries.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "1a932031ffdf7a07800d30b2d898fc34" + }, + "permission.romhackplaza_canEditOthersEntries.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "83d885098bc54e2afa37b3045c8048f3" + }, + "permission.romhackplaza_canModerateEntries.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "7ab831a3557b53a4a63ac279cd33fc36" + }, + "permission.romhackplaza_canSeeHiddenEntries.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "20fbb37e0be574bb4060c16c1caf6d50" + }, + "permission.romhackplaza_canSeeLockedEntries.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "4738ddb90744d6caf4e46335eeac511a" + }, + "permission.romhackplaza_canSeeOthersDrafts.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "4c2c7800c562085f51a3b486dfb8e5bb" + }, + "permission.romhackplaza_canSeeRejectedEntries.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "827c586329fad5466cccf547f5011bea" + }, "permission.romhackplaza_canSubmitEntry.txt": { "global_cache": false, "version_id": 1000000, "version_string": "1.0.0", "hash": "d62432dfaf4d83315ed838ce10794fa1" }, + "permission.romhackplaza_canSubmitEntryInPublished.txt": { + "global_cache": false, + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "40e2c757fc3f0056a40aa98dec7d2d25" + }, "permission.romhackplaza_canSubmitTempFile.txt": { "global_cache": false, "version_id": 1000000, diff --git a/_output/templates/_metadata.json b/_output/templates/_metadata.json index 82b0a23..d25982e 100644 --- a/_output/templates/_metadata.json +++ b/_output/templates/_metadata.json @@ -3,5 +3,20 @@ "version_id": 1000000, "version_string": "1.0.0", "hash": "19cd05c4ab254dbad0abfd0c6b8c3456" + }, + "public/approval_item_club_request.html": { + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "39492e4fb48e7aa1622a6bb4371a36f4" + }, + "public/club_request_form.html": { + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "5e1c397d93134aaa7164301d5a3553ce" + }, + "public/report_content_romhackplaza_entry.html": { + "version_id": 1000000, + "version_string": "1.0.0", + "hash": "d6c5c25a9af81a7da2bd8e2b9f74229e" } } \ No newline at end of file