From 48721c85ebcfa973ee81719d2467ca80e4253dc9 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Fri, 01 May 2026 17:30:03 +0000
Subject: [PATCH] =Edmonton Ink hard test begins! Real testing of the managers and reset routes will commence. So far, just ensuring our classes are all loaded correctly: Site() and its sub-classes Membership, Login, etc. Care should be taken to load conditionally on 'init', as we finish defining most settings by 'plugins_loaded' at priority 5

---
 inc/managers/RoleManager.php |  174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 162 insertions(+), 12 deletions(-)

diff --git a/inc/managers/RoleManager.php b/inc/managers/RoleManager.php
index 863ff46..b275f12 100644
--- a/inc/managers/RoleManager.php
+++ b/inc/managers/RoleManager.php
@@ -13,6 +13,7 @@
 {
     private array $roles;
 	private array $content;
+	private array $subTypes = [];
 
     public function __construct()
     {
@@ -26,8 +27,23 @@
 		   Registrar::getFeatured('is_content', 'term')
 	   ));
 	   add_action('set_user_role', [$this, 'updateRoles'], 10, 3);
+
+	   $this->checkRoleSubTypes();
     }
 
+	public function checkRoleSubTypes():void
+	{
+		foreach ($this->roles as $role) {
+			$registrar = Registrar::getInstance($role);
+			if ($registrar->getUserSubtype()){
+				$this->subTypes[jvbCheckBase($registrar->getUserSubtype())] = $registrar->getCreatable();
+			}
+		}
+		if (!empty($this->subTypes)) {
+			add_action('set_object_terms', [$this, 'maybeSwitchPermissions'],10, 6);
+		}
+	}
+
 	public function updateRoles(int $userID, string $role, array $oldRoles):void
 	{
 		if (doing_action('set_user_role') > 1) {
@@ -93,7 +109,6 @@
 		$roles = array_keys($user->roles);
 
 		foreach ($roles as $role) {
-			$role = jvbNoBase($role);
 			$registrar = Registrar::getInstance($role);
 			if (!$registrar) {
 				return false;
@@ -217,7 +232,7 @@
         if (!in_array($type, $this->roles)) {
             return false;
         }
-        $link = get_user_meta($user->ID, BASE.'link', true);
+        $link = get_user_meta($user->ID, BASE.'profile_link', true);
         if ($link === '') {
             $type = BASE.$type;
             $name = $user->display_name;
@@ -230,8 +245,8 @@
                 'post_author'   => $user->ID,
             ]);
 			if ($link) {
-				update_user_meta($user->ID, BASE.'link', $link);
-				update_post_meta($link, BASE.'link', $user->ID);
+				update_user_meta($user->ID, BASE.'profile_link', $link);
+				update_post_meta($link, BASE.'profile_link', $user->ID);
 			}
         }
         return $link;
@@ -259,8 +274,8 @@
 		if ($registrar->hasFeature('has_dashboard') ?? false) {
 			$admin_role = get_role('administrator');
 			if ($admin_role) {
-				$admin_role->add_cap("manage_{$role_name}s", true);
-				$admin_role->add_cap("edit_{$role_name}_settings", true);
+				$admin_role->add_cap("manage_{$role_name}s");
+				$admin_role->add_cap("edit_{$role_name}_settings");
 			}
 		}
 	}
@@ -392,12 +407,15 @@
 
 		return [
 			"edit_{$content}",
+			"edit_published_{$content}",
 			"read_{$content}",
 			"delete_{$content}",
+			"delete_published_{$content}",
 			"edit_{$plural}",
-			"edit_others_{$plural}",
 			"publish_{$plural}",
 			"read_private_{$plural}",
+			"edit_private_{$plural}",
+			"delete_private_{$plural}",
 		];
 	}
 	protected function getOthersCapabilities(string $content):array
@@ -410,9 +428,6 @@
 		return [
 			"edit_others_{$plural}",
 			"delete_others_{$plural}",
-			"read_private_{$plural}",
-			"edit_private_{$plural}",
-			"delete_private_{$plural}",
 		];
 	}
 
@@ -431,12 +446,60 @@
 		return str_replace(' ', '_', $content.'s');
 	}
 
-	public function activate(): void
+	public static function activate(): void
 	{
+		error_log('[RoleManager]::activate');
+		error_log('Registering roles...');
+		$instance = new self;
 		foreach (Registrar::getRegistered('user') as $role) {
-			$this->registerRole($role);
+			$instance->registerRole($role);
 		}
+		error_log('Roles registered!');
+		error_log('Removing unneeded roles...');
+		remove_role('contributor');
+		remove_role('author');
+		remove_role('editor');
+		error_log('Roles removed!');
+
+		error_log('Adding Admin Capabilities');
+		$instance->addAdminCaps();
+		error_log('Ensuring Existing User\'s Roles...');
+		$instance->ensureRoleCaps();
+		error_log('Roles activated!');
 	}
+		protected function addAdminCaps():void
+		{
+			$users = get_users(['role' => 'administrator']);
+			foreach (array_merge(Registrar::getRegistered('post'), Registrar::getFeatured('is_content')) as $slug) {
+				$this->grantRoleCapabilities('administrator', $slug);
+				$this->grantRoleOthersCapabilities('administrator', $slug);
+
+				foreach ($users as $user) {
+					$this->grantContent($user, $slug);
+					$this->grantOthersContent($user, $slug);
+				}
+			}
+		}
+		protected function ensureRoleCaps():void
+		{
+			$roles = Registrar::getRegistered('user');
+			foreach ($roles as $role) {
+				$registrar = Registrar::getInstance($role);
+				$creatable = $registrar->getCreatable();
+				$manageable = $registrar->getManageOthers();
+				if (!empty($creatable) || !empty($manageable)) {
+					$users = get_users(['role' => jvbCheckBase($role)]);
+					foreach ($users as $user) {
+						foreach ($creatable as $slug) {
+							$this->grantContent($user, $slug);
+						}
+						foreach ($manageable as $slug) {
+							$this->grantOthersContent($user, $slug);
+						}
+					}
+				}
+			}
+		}
 
 	/******************************************************************
 	 * OWNABLE and MANAGABLE terms (ie: tattoo shops)
@@ -758,4 +821,91 @@
 		}
 		return null;
 	}
+
+	public function maybeSwitchPermissions(int $object_id, array $terms, array $tt_ids, string $taxonomy, bool $append, array $old_tt_ids):void
+	{
+		//This shouldn't happen, but whatever
+		if (empty($this->subTypes)) {
+			return;
+		}
+
+		if (!in_array($taxonomy, array_keys($this->subTypes))) {
+			return;
+		}
+
+		$new = array_diff($tt_ids, $old_tt_ids);
+		$old = array_diff($old_tt_ids, $tt_ids);
+
+		$userID = (int)get_post_meta($object_id, BASE.'profile_link',true);
+		if ($userID === 0) {
+			return;
+		}
+		$user = get_userdata($userID);
+		if (!$user) {
+			return;
+		}
+
+		//Revoke old first
+		if (!empty($old)) {
+			$old = array_filter(array_map(function ($id) use ($taxonomy) {
+				$termID = $this->getTermIDFromTTID($id);
+				return $this->getRootTermSlug($termID, $taxonomy);
+			}, $old));
+			foreach ($old as $slug) {
+				if (!array_key_exists($slug, $this->subTypes[$taxonomy])) {
+					error_log('[RoleManager]::maybeSwitchPermissions Could not find creatable types for role subtype '.$slug);
+					continue;
+				}
+				foreach ($this->subTypes[$taxonomy][$slug] ?? [] as $s) {
+					$this->grantContent($user, $s, false);
+				}
+			}
+		}
+
+		if (!empty($new)) {
+			$new = array_filter(array_map(function ($id) use ($taxonomy){
+				$termID = $this->getTermIDFromTTID($id);
+				return $this->getRootTermSlug($termID, $taxonomy);
+			}, $new));
+			foreach ($new as $slug) {
+				if (!array_key_exists($slug, $this->subTypes[$taxonomy])) {
+					error_log('[RoleManager]::maybeSwitchPermissions Could not find creatable types for role subtype '.$slug);
+					continue;
+				}
+				foreach ($this->subTypes[$taxonomy][$slug] ?? [] as $s) {
+					$this->grantContent($user, $s);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Helper function to get term_id from term_taxonomy_id
+	 * @param int $tt_id
+	 *
+	 * @return int
+	 */
+	private function getTermIDFromTTID(int $tt_id):int
+	{
+		global $wpdb;
+		return $wpdb->get_var($wpdb->prepare(
+			"SELECT term_id FROM {$wpdb->term_taxonomy} WHERE term_taxonomy_id = %d",
+			$tt_id
+		));
+	}
+
+	private function getRootTermSlug(int $termID, string $taxonomy): string|false
+	{
+		$term = get_term($termID, $taxonomy);
+		if (!$term || is_wp_error($term)) {
+			return false;
+		}
+		while ($term->parent !== 0) {
+			$term = get_term($term->parent, $taxonomy);
+			if (!$term || is_wp_error($term)) {
+				return false;
+			}
+		}
+		return $term->slug;
+	}
 }

--
Gitblit v1.10.0