forked from GNUsocial/gnu-social
		
	[TAGS] Fix some minor logic issues with Actor Tags and Circles
This commit is contained in:
		| @@ -68,7 +68,7 @@ class RelatedTags extends Plugin | ||||
|                 'related-actor-tags-' . implode('-', $tags), | ||||
|                 fn () => DB::sql( | ||||
|                     <<<'EOQ' | ||||
|                         select distinct on (at.canonical) canonical, at.tagger, at.tagged, at.tag, at.modified | ||||
|                         select distinct on (at.canonical) canonical, at.tagger, at.tagged, at.tag, at.use_canonical, at.modified | ||||
|                         from actor_tag at | ||||
|                         where at.tagged in (select at.tagged from actor_tag at where at.canonical in (:tags)) | ||||
|                               and not at.canonical in (:tags) | ||||
|   | ||||
| @@ -378,16 +378,14 @@ class Actor extends Entity | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param array      $tags     array of strings to become self tags | ||||
|      * @param array $tags array of strings to become self tags | ||||
|      * @param null|array $existing array of existing self tags (ActorTag[]) | ||||
|      * | ||||
|      * @throws \App\Util\Exception\DuplicateFoundException | ||||
|      * @throws NotFoundException | ||||
|      * | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function setSelfTags(array $tags, ?array $existing = null): self | ||||
|         public function setSelfTags(array $tags, ?array $existing = null): self | ||||
|     { | ||||
|         $tags = F\filter($tags, fn ($tag) => Nickname::isCanonical($tag)); // TODO: Have an actual #Tag test | ||||
|         $tags = array_unique($tags); | ||||
|         if (\is_null($existing)) { | ||||
|             [$_, $existing] = $this->getSelfTags(); | ||||
| @@ -398,13 +396,12 @@ class Actor extends Entity | ||||
|         $actor_tags_to_remove = F\filter($existing, fn ($actor_tag) => \in_array($actor_tag->getTag(), $tags_to_remove)); | ||||
|         foreach ($tags_to_add as $tag) { | ||||
|             $canonical_tag = TagComponent::canonicalTag($tag, $this->getTopLanguage()->getLocale()); | ||||
|             DB::persist(ActorCircle::create(['tagger' => $this->getId(), 'tag' => $canonical_tag, 'private' => false])); | ||||
|             DB::persist(ActorTag::create(['tagger' => $this->id, 'tagged' => $this->id, 'tag' => $tag, 'canonical' => $canonical_tag, 'use_canonical' => true])); // TODO make use canonical configurable | ||||
|             DB::persist(ActorCircle::create(['tagger' => $this->getId(), 'tag' => $tag, 'private' => false])); | ||||
|             DB::persist(ActorTag::create(['tagger' => $this->id, 'tagged' => $this->id, 'tag' => $tag, 'canonical' => $canonical_tag, 'use_canonical' => false])); // TODO make use canonical configurable | ||||
|         } | ||||
|         foreach ($actor_tags_to_remove as $actor_tag) { | ||||
|             $canonical_tag = TagComponent::canonicalTag($actor_tag->getTag(), $this->getTopLanguage()->getLocale()); | ||||
|             DB::removeBy('actor_tag', ['tagger' => $this->getId(), 'tagged' => $this->getId(), 'canonical' => $canonical_tag]); | ||||
|             DB::removeBy('actor_circle', ['tagger' => $this->getId(), 'tag' => $canonical_tag]); // TODO only remove if unused | ||||
|             DB::removeBy('actor_tag', ['tagger' => $this->getId(), 'tagged' => $this->getId(), 'tag' => $actor_tag->getTag(), 'use_canonical' => $actor_tag->getUseCanonical()]); | ||||
|             DB::removeBy('actor_circle', ['tagger' => $this->getId(), 'tag' => $actor_tag->getTag()]); // TODO only remove if unused | ||||
|         } | ||||
|         Cache::delete(self::cacheKeys($this->getId())['tags']); | ||||
|         Cache::delete(self::cacheKeys($this->getId(), $this->getId())['tags']); | ||||
|   | ||||
| @@ -28,6 +28,8 @@ use DateTimeInterface; | ||||
|  | ||||
| /** | ||||
|  * Entity for List of actors | ||||
|  * This entity only makes sense when considered together with the ActorTag one. | ||||
|  * Because, every circle entry will be an ActorTag. | ||||
|  * | ||||
|  * @category  DB | ||||
|  * @package   GNUsocial | ||||
| @@ -166,8 +168,10 @@ class ActorCircle extends Entity | ||||
|             'description' => 'a actor can have lists of actors, to separate their feed', | ||||
|             'fields'      => [ | ||||
|                 'id'          => ['type' => 'serial',    'not null' => true, 'description' => 'unique identifier'], | ||||
|                 // An actor can be tagged by many actors | ||||
|                 'tagger'      => ['type' => 'int',       'foreign key' => true, 'target' => 'Actor.id', 'multiplicity' => 'many to one', 'name' => 'actor_list_tagger_fkey', 'not null' => true, 'description' => 'user making the tag'], | ||||
|                 'tag'         => ['type' => 'varchar',   'length' => 64, 'foreign key' => true, 'target' => 'ActorTag.canonical', 'multiplicity' => 'many to one', 'not null' => true, 'description' => 'actor tag'], // Join with ActorTag // // so, Doctrine doesn't like that the target is not unique, even though the pair is | ||||
|                 // Many Actor Circles can reference (and probably will) an Actor Tag | ||||
|                 'tag'         => ['type' => 'varchar',   'length' => 64, 'foreign key' => true, 'target' => 'ActorTag.tag', 'multiplicity' => 'many to one', 'not null' => true, 'description' => 'actor tag'], // Join with ActorTag // // so, Doctrine doesn't like that the target is not unique, even though the pair is | ||||
|                 'description' => ['type' => 'text',      'description' => 'description of the people tag'], | ||||
|                 'private'     => ['type' => 'bool',      'default' => false, 'description' => 'is this tag private'], | ||||
|                 'created'     => ['type' => 'datetime',  'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], | ||||
|   | ||||
| @@ -24,6 +24,8 @@ use DateTimeInterface; | ||||
|  | ||||
| /** | ||||
|  * Entity for actor circle subscriptions | ||||
|  * This entity only makes sense when considered with the ActorCircle entity. | ||||
|  * Because you can only subscribe a Circle that exists. | ||||
|  * | ||||
|  * @category  DB | ||||
|  * @package   GNUsocial | ||||
| @@ -96,10 +98,11 @@ class ActorCircleSubscription extends Entity | ||||
|     public static function schemaDef(): array | ||||
|     { | ||||
|         return [ | ||||
|             'name' => 'actor_tag_subscription', | ||||
|             'name' => 'actor_circle_subscription', | ||||
|             'fields' => [ | ||||
|                 'actor_id'  => ['type' => 'int', 'foreign key' => true, 'target' => 'Actor.id', 'multiplicity' => 'one to one', 'name' => 'actor_circle_subscription_actor_id_fkey', 'not null' => true, 'description' => 'foreign key to actor table'], | ||||
|                 'circle_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'ActorCircle.id', 'multiplicity' => 'one to one', 'name' => 'actor_circle_subscription_actor_circle_fkey', 'not null' => true, 'description' => 'foreign key to actor_circle'], | ||||
|                 // An actor subscribes many circles; A Circle is subscribed by many actors. | ||||
|                 'circle_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'ActorCircle.id', 'multiplicity' => 'one to many', 'name' => 'actor_circle_subscription_actor_circle_fkey', 'not null' => true, 'description' => 'foreign key to actor_circle'], | ||||
|                 'created'   => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], | ||||
|                 'modified'  => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], | ||||
|             ], | ||||
|   | ||||
| @@ -30,6 +30,10 @@ use DateTimeInterface; | ||||
|  | ||||
| /** | ||||
|  * Entity for Actor Tag | ||||
|  * This entity represents the relationship between an Actor and a Tag. | ||||
|  * That relationship works as follows: | ||||
|  * An Actor A tags an Actor B (which can be A - a self tag). | ||||
|  * For every tagging that happens between two actors, a new ActorTag is born. | ||||
|  * | ||||
|  * @category  DB | ||||
|  * @package   GNUsocial | ||||
| @@ -39,6 +43,7 @@ use DateTimeInterface; | ||||
|  * @author    Mikael Nordfeldth <mmn@hethane.se> | ||||
|  * @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org | ||||
|  * @author    Hugo Sales <hugo@hsal.es> | ||||
|  * @author    Diogo Peralta Cordeiro <@diogo.site> | ||||
|  * @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org | ||||
|  * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | ||||
|  */ | ||||
| @@ -156,10 +161,10 @@ class ActorTag extends Entity | ||||
|                 'use_canonical' => ['type' => 'bool',      'not null' => true, 'description' => 'whether the user wanted to block canonical tags'], | ||||
|                 'modified'      => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], | ||||
|             ], | ||||
|             'primary key' => ['tagger', 'tagged', 'canonical'], | ||||
|             'primary key' => ['tagger', 'tagged', 'tag', 'use_canonical'], | ||||
|             'indexes'     => [ | ||||
|                 'actor_tag_modified_idx'         => ['modified'], | ||||
|                 'actor_tag_tagger_canonical_idx' => ['tagger', 'canonical'], // For Circles | ||||
|                 'actor_tag_tagger_tag_idx' => ['tagger', 'tag'], // For Circles | ||||
|                 'actor_tag_tagged_idx'           => ['tagged'], | ||||
|             ], | ||||
|         ]; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user