defineTables(); } protected function defineTables():void { $types = implode(',', array_map(function($item) { return "`{$item}`"; },Registrar::getFeatured('verify_entry'))); $table = CustomTable::for('verify_entry'); $table->setColumns([ 'id' => 'bigint(20) unsigned NOT NULL AUTO_INCREMENT', 'user_id' => "{$table->getUserIDType()} NOT NULL", 'content_id' => "{$table->getPostIDType()} NOT NULL", 'content_type' => 'varchar(255) NOT NULL', 'term_id' => "{$table->getTermIDType()} NOT NULL", 'taxonomy' => "ENUM({$types}) NOT NULL", 'status' => "ENUM('requested', 'rejected','accepted') NOT NULL DEFAULT 'requested'", 'result' => 'JSON DEFAULT NULL', 'notes' => 'text DEFAULT NULL', 'created_date' => 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP', 'updated_date' => 'timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP', ]); $table->setKeys([ ['key' => 'PRIMARY', 'value' => '(`id`)'], ['key' => 'UNIQUE', 'value' => 'content_term (`content_id`, `term_id`)'], 'user_id (`user_id`)', 'term_id (`term_id`)', 'status (`term_id`, `status`)' ]); $base = BASE; $table->setConstraints([ "CONSTRAINT `{$base}verify_entry_user` FOREIGN KEY (`user_id`) REFERENCES `{$table->getUserTable()}` (`ID`) ON DELETE CASCADE", "CONSTRAINT `{$base}verify_entry_term` FOREIGN KEY (`term_id`) REFERENCES `{$table->getTermTable()}` (`term_id`) ON DELETE CASCADE", ]); $table->defineTable(); $this->table = $table; } protected function response(?bool $success = null, string $message = ''):array { $response = [ 'success' => is_null($success) ? 'partial' : $success, ]; if (!empty($message)) { $response['message'] = $message; } return $response; } public function requestEntry(int $userID, int $termID, string $taxonomy):array { $user = get_userdata($userID); if (!$user || is_wp_error($user)) { return $this->response(false, 'User does not exist'); } $term = get_term($termID, jvbCheckBase($taxonomy)); if (!$term || is_wp_error($term)) { return $this->response(false, 'Term does not exist'); } $profile = get_user_meta($userID, BASE.'link', true); if (empty($profile)) { return $this->response(false, 'No Profile found'); } $managers = jvbGetTermOwners($termID); if (in_array($userID, $managers)) { wp_set_object_terms($profile, $termID, jvbCheckBase($taxonomy)); return $this->response(true, 'User is manager'); } $total = $this->table->pluck('user_id', [ 'user_id' => $userID, 'status' => 'requested' ]); if (count($total) >= $this->max) { return $this->response(false, 'User already has maximum requests'); } $existing = $this->table->get([ 'user_id' => $userID, 'term_id' => $termID ]); if ($existing) { return $this->response(false, 'Existing pending request found. Please wait for response.'); } $request = $this->table->insert([ 'user_id' => $userID, 'content_id'=> (int)$profile, 'content_type'=> jvbNoBase(get_post_type($profile)), 'term_id' => $termID, 'taxonomy' => jvbNoBase($taxonomy) ]); if ($request && !empty($owners)) { JVB()->notification()->notify($owners,'entry_requested',$userID, [ 'target_id' => $termID, 'target_type' => $taxonomy ]); } return $this->response(true, 'Request has been sent'); } protected function actionEntry(bool $approve, int $userID, int $requestID, ?string $notes = null):array { $request = $this->table->get(['id' => $requestID]); if (!$request) { return $this->response(false, 'Request does not exist'); } $termID = $request['term_id']; $owners = jvbGetTermOwners($termID); if (!user_can($userID, 'can_manage_'.$termID) || !in_array($userID, $owners)) { return $this->response(false, 'User does not exist'); } $result = $this->table->update([ 'status' => ($approve ? 'accepted' : 'rejected'), 'notes' => $notes ], [ 'id' => $requestID ]); if ($approve) { wp_set_object_terms($request['content_id'], $termID, jvbCheckBase($request['taxonomy'])); } JVB()->notification()?->notify($request['user_id'],$approve ? 'entry_approved' : 'entry_denied',$userID); //TODO: What if there are multiple managers, and one approved the request? Do we just delete the notification? JVB()->notification()?->unnotify($owners, 'entry_requested', $request['user_id'], [ 'target_id' => $termID, 'target_type' => $request['taxonomy'] ]); return $this->response(true, 'Request has been '. $approve ? 'approved' : 'denied'); } public function approveEntry(int $userID, int $requestID, ?string $notes = null):array { return $this->actionEntry(true, $userID, $requestID, $notes); } public function denyEntry(int $userID, int $requestID, ?string $notes = null):array { return $this->actionEntry(false, $userID, $requestID, $notes); } }