forked from GNUsocial/gnu-social
		
	[PLUGIN][AttachmentCollections] Restore functionality
Some minor corrections
This commit is contained in:
		| @@ -94,7 +94,7 @@ class Attachment extends Controller | ||||
|                     'title'            => $res['title'], | ||||
|                     'attachment'       => $res['attachment'], | ||||
|                     'note'             => $res['note'], | ||||
|                     'right_panel_vars' => ['attachment_id' => $attachment_id], | ||||
|                     'right_panel_vars' => ['attachment_id' => $attachment_id, 'note_id' => $note_id], | ||||
|                 ]; | ||||
|             }); | ||||
|         } catch (NotFoundException) { | ||||
|   | ||||
							
								
								
									
										11
									
								
								components/Collection/Collection.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								components/Collection/Collection.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types = 1); | ||||
|  | ||||
| namespace Component\Collection; | ||||
|  | ||||
| use App\Core\Modules\Component; | ||||
|  | ||||
| class Collection extends Component | ||||
| { | ||||
| } | ||||
| @@ -2,9 +2,10 @@ | ||||
| 
 | ||||
| declare(strict_types = 1); | ||||
| 
 | ||||
| namespace Plugin\AttachmentCollections\Entity; | ||||
| namespace Component\Collection\Entity; | ||||
| 
 | ||||
| use App\Core\Entity; | ||||
| use function mb_substr; | ||||
| 
 | ||||
| class Collection extends Entity | ||||
| { | ||||
| @@ -12,7 +13,7 @@ class Collection extends Entity | ||||
|     // {{{ Autocode
 | ||||
|     // @codeCoverageIgnoreStart
 | ||||
|     private int $id; | ||||
|     private ?string $name = null; | ||||
|     private string $name; | ||||
|     private int $actor_id; | ||||
| 
 | ||||
|     public function setId(int $id): self | ||||
| @@ -26,13 +27,13 @@ class Collection extends Entity | ||||
|         return $this->id; | ||||
|     } | ||||
| 
 | ||||
|     public function setName(?string $name): self | ||||
|     public function setName(string $name): self | ||||
|     { | ||||
|         $this->name = \is_null($name) ? null : mb_substr($name, 0, 255); | ||||
|         $this->name = mb_substr($name, 0, 255); | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function getName(): ?string | ||||
|     public function getName(): string | ||||
|     { | ||||
|         return $this->name; | ||||
|     } | ||||
| @@ -54,10 +55,10 @@ class Collection extends Entity | ||||
|     public static function schemaDef() | ||||
|     { | ||||
|         return [ | ||||
|             'name'   => 'attachment_collection', | ||||
|             'name'   => 'collection', | ||||
|             'fields' => [ | ||||
|                 'id'       => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'], | ||||
|                 'name'     => ['type' => 'varchar', 'length' => 255, 'description' => 'collection\'s name'], | ||||
|                 'name'     => ['type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'collection\'s name'], | ||||
|                 'actor_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Actor.id', 'multiplicity' => 'one to many', 'not null' => true, 'description' => 'foreign key to actor table'], | ||||
|             ], | ||||
|             'primary key' => ['id'], | ||||
| @@ -33,7 +33,6 @@ namespace Plugin\AttachmentCollections; | ||||
|  | ||||
| use App\Core\DB\DB; | ||||
| use App\Core\Event; | ||||
| use App\Util\Exception\RedirectException; | ||||
| use App\Core\Form; | ||||
| use function App\Core\I18n\_m; | ||||
| use App\Core\Modules\Plugin; | ||||
| @@ -42,11 +41,12 @@ use App\Core\Router\Router; | ||||
| use App\Entity\Feed; | ||||
| use App\Entity\LocalUser; | ||||
| use App\Util\Common; | ||||
| use App\Util\Exception\RedirectException; | ||||
| use App\Util\Formatting; | ||||
| use App\Util\Nickname; | ||||
| use Component\Collection\Entity\Collection; | ||||
| use Plugin\AttachmentCollections\Controller as C; | ||||
| use Plugin\AttachmentCollections\Entity\Collection; | ||||
| use Plugin\AttachmentCollections\Entity\CollectionEntry; | ||||
| use Plugin\AttachmentCollections\Entity\AttachmentCollectionEntry; | ||||
| use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | ||||
| use Symfony\Component\Form\Extension\Core\Type\SubmitType; | ||||
| use Symfony\Component\Form\Extension\Core\Type\TextType; | ||||
| @@ -80,6 +80,7 @@ class AttachmentCollections extends Plugin | ||||
|         ); | ||||
|         return Event::next; | ||||
|     } | ||||
|  | ||||
|     public function onCreateDefaultFeeds(int $actor_id, LocalUser $user, int &$ordering) | ||||
|     { | ||||
|         DB::persist(Feed::create([ | ||||
| @@ -91,6 +92,7 @@ class AttachmentCollections extends Plugin | ||||
|         ])); | ||||
|         return Event::next; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Append Attachment Collections widget to the right panel. | ||||
|      * It's compose of two forms: one to select collections to add | ||||
| @@ -106,23 +108,23 @@ class AttachmentCollections extends Plugin | ||||
|             return Event::next; | ||||
|         } | ||||
|  | ||||
|         $colls = DB::dql( | ||||
|             'select coll from Plugin\AttachmentCollections\Entity\Collection coll where coll.actor_id = :id', | ||||
|             ['id' => $user->getId()], | ||||
|         ); | ||||
|         $collections = DB::findBy(Collection::class, ['actor_id' => $user->getId()]); | ||||
|  | ||||
|         // add to collection form | ||||
|         $attachment_id = $vars['vars']['attachment_id']; | ||||
|         $note_id       = $vars['vars']['note_id']; | ||||
|         $choices       = []; | ||||
|         foreach ($colls as $col) { | ||||
|         foreach ($collections as $col) { | ||||
|             $choices[$col->getName()] = $col->getId(); | ||||
|         } | ||||
|         $already_selected = DB::dql( | ||||
|             'select entry.collection_id from attachment_album_entry entry ' | ||||
|             . 'inner join attachment_collection collection ' | ||||
|                 . 'with collection.id = entry.collection_id ' | ||||
|             . 'where entry.attachment_id = :aid and collection.actor_id = :id', | ||||
|             ['aid' => $attachment_id, 'id' => $user->getId()], | ||||
|             <<<'EOF' | ||||
|                 SELECT entry.collection_id FROM \Plugin\AttachmentCollections\Entity\AttachmentCollectionEntry AS entry | ||||
|                 INNER JOIN \Component\Collection\Entity\Collection AS attachment_collection | ||||
|                 WITH attachment_collection.id = entry.collection_id | ||||
|                 WHERE entry.attachment_id = :attach_id AND entry.note_id = :note_id AND attachment_collection.actor_id = :id | ||||
|                 EOF, | ||||
|             ['attach_id' => $attachment_id, 'note_id' => $note_id, 'id' => $user->getId()], | ||||
|         ); | ||||
|         $already_selected = array_map(fn ($x) => $x['collection_id'], $already_selected); | ||||
|         $add_form         = Form::create([ | ||||
| @@ -150,24 +152,23 @@ class AttachmentCollections extends Plugin | ||||
|             $collections = $add_form->getData()['collections']; | ||||
|             $removed     = array_filter($already_selected, fn ($x) => !\in_array($x, $collections)); | ||||
|             $added       = array_filter($collections, fn ($x) => !\in_array($x, $already_selected)); | ||||
|             if (\count($removed)) { | ||||
|                 DB::dql( | ||||
|                     'delete from Plugin\AttachmentCollections\Entity\CollectionEntry entry ' | ||||
|                     . 'where entry.attachment_id = :aid and entry.collection_id in (' | ||||
|                         . 'select collection.id from Plugin\AttachmentCollections\Entity\Collection collection ' | ||||
|                         . 'where collection.id in (:ids) ' | ||||
|                         // prevent user from deleting something (s)he doesn't own: | ||||
|                         . 'and collection.actor_id = :id' | ||||
|                     . ')', | ||||
|                     ['aid' => $attachment_id, 'id' => $user->getId(), 'ids' => $removed], | ||||
|                 ); | ||||
|             if (\count($removed) > 0) { | ||||
|                 DB::dql(<<<'EOF' | ||||
|                         DELETE FROM \Plugin\AttachmentCollections\Entity\AttachmentCollectionEntry AS entry | ||||
|                         WHERE entry.attachment_id = :attach_id AND entry.note_id = :note_id | ||||
|                         AND entry.collection_id IN ( | ||||
|                             SELECT album.id FROM \Component\Collection\Entity\Collection AS album | ||||
|                             WHERE album.actor_id = :user_id | ||||
|                               AND album.id IN (:ids) | ||||
|                         ) | ||||
|                     EOF, ['attach_id' => $attachment_id, 'note_id' => $note_id, 'user_id' => $user->getId(), 'ids' => $removed]); | ||||
|             } | ||||
|             $collection_ids = array_map(fn ($x) => $x->getId(), $colls); | ||||
|             foreach ($added as $cid) { | ||||
|                 // prevent user from putting something in a collection (s)he doesn't own: | ||||
|                 if (\in_array($cid, $collection_ids)) { | ||||
|                     DB::persist(CollectionEntry::create([ | ||||
|                 if (\in_array($cid, $collections)) { | ||||
|                     DB::persist(AttachmentCollectionEntry::create([ | ||||
|                         'attachment_id' => $attachment_id, | ||||
|                         'note_id'       => $note_id, | ||||
|                         'collection_id' => $cid, | ||||
|                     ])); | ||||
|                 } | ||||
| @@ -200,9 +201,9 @@ class AttachmentCollections extends Plugin | ||||
|                 'actor_id' => $user->getId(), | ||||
|             ]); | ||||
|             DB::persist($coll); | ||||
|             DB::flush(); | ||||
|             DB::persist(CollectionEntry::create([ | ||||
|             DB::persist(AttachmentCollectionEntry::create([ | ||||
|                 'attachment_id' => $attachment_id, | ||||
|                 'note_id'       => $note_id, | ||||
|                 'collection_id' => $coll->getId(), | ||||
|             ])); | ||||
|             DB::flush(); | ||||
| @@ -212,13 +213,14 @@ class AttachmentCollections extends Plugin | ||||
|         $res[] = Formatting::twigRenderFile( | ||||
|             'AttachmentCollections/widget.html.twig', | ||||
|             [ | ||||
|                 'has_collections' => $colls, | ||||
|                 'has_collections' => $collections, | ||||
|                 'add_form'        => $add_form->createView(), | ||||
|                 'create_form'     => $create_form->createView(), | ||||
|             ], | ||||
|         ); | ||||
|         return Event::next; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Output our dedicated stylesheet | ||||
|      * | ||||
|   | ||||
| @@ -24,13 +24,14 @@ declare(strict_types = 1); | ||||
| namespace Plugin\AttachmentCollections\Controller; | ||||
|  | ||||
| use App\Core\DB\DB; | ||||
| use App\Util\Exception\RedirectException; | ||||
| use App\Core\Form; | ||||
| use function App\Core\I18n\_m; | ||||
| use App\Core\Router\Router; | ||||
| use App\Entity\LocalUser; | ||||
| use App\Util\Common; | ||||
| use App\Util\Exception\RedirectException; | ||||
| use Component\Collection\Entity\Collection; | ||||
| use Component\Feed\Util\FeedController; | ||||
| use Plugin\AttachmentCollections\Entity\Collection; | ||||
| use Symfony\Component\Form\Extension\Core\Type\SubmitType; | ||||
| use Symfony\Component\Form\Extension\Core\Type\TextType; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| @@ -39,13 +40,15 @@ class Controller extends FeedController | ||||
| { | ||||
|     public function collectionsByActorNickname(Request $request, string $nickname): array | ||||
|     { | ||||
|         $user = DB::findOneBy('local_user', ['nickname' => $nickname]); | ||||
|         $user = DB::findOneBy(LocalUser::class, ['nickname' => $nickname]); | ||||
|         return self::collectionsView($request, $user->getId(), $nickname); | ||||
|     } | ||||
|  | ||||
|     public function collectionsViewByActorId(Request $request, int $id): array | ||||
|     { | ||||
|         return self::collectionsView($request, $id, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Generate Collections page | ||||
|      * | ||||
| @@ -56,11 +59,8 @@ class Controller extends FeedController | ||||
|      */ | ||||
|     public function collectionsView(Request $request, int $id, ?string $nickname): array | ||||
|     { | ||||
|         $collections = DB::dql( | ||||
|             'select collection from Plugin\AttachmentCollections\Entity\Collection collection ' | ||||
|             . 'where collection.actor_id = :id', | ||||
|             ['id' => $id], | ||||
|         ); | ||||
|         $collections = DB::findBy(Collection::class, ['actor_id' => $id]); | ||||
|  | ||||
|         // create collection form | ||||
|         $create = null; | ||||
|         if (Common::user()?->getId() === $id) { | ||||
| @@ -92,16 +92,17 @@ class Controller extends FeedController | ||||
|         } | ||||
|  | ||||
|         // We need to inject some functions in twig, | ||||
|         // but i don't want to create an enviroment for this | ||||
|         // but I don't want to create an environment for this | ||||
|         // as twig docs suggest in https://twig.symfony.com/doc/2.x/advanced.html#functions. | ||||
|         // | ||||
|         // Instead, I'm using an anonymous class to encapsulate | ||||
|         // the functions and passing how the class to the template. | ||||
|         // It's suggested at https://stackoverflow.com/a/50364502. | ||||
|         // the functions and passing that class to the template. | ||||
|         // This is suggested at https://stackoverflow.com/a/50364502. | ||||
|         $fn = new class($id, $nickname, $request) { | ||||
|             private $id; | ||||
|             private $nick; | ||||
|             private $request; | ||||
|  | ||||
|             public function __construct($id, $nickname, $request) | ||||
|             { | ||||
|                 $this->id      = $id; | ||||
| @@ -156,6 +157,7 @@ class Controller extends FeedController | ||||
|                 } | ||||
|                 return $edit->createView(); | ||||
|             } | ||||
|  | ||||
|             // creating the remove form | ||||
|             public function rmForm($collection) | ||||
|             { | ||||
| @@ -189,23 +191,29 @@ class Controller extends FeedController | ||||
|  | ||||
|     public function collectionNotesByNickname(Request $request, string $nickname, int $cid): array | ||||
|     { | ||||
|         $user = DB::findOneBy('local_user', ['nickname' => $nickname]); | ||||
|         $user = DB::findOneBy(LocalUser::class, ['nickname' => $nickname]); | ||||
|         return self::collectionNotesByActorId($request, $user->getId(), $cid); | ||||
|     } | ||||
|  | ||||
|     public function collectionNotesByActorId(Request $request, int $id, int $cid): array | ||||
|     { | ||||
|         $collection = DB::findOneBy('attachment_collection', ['id' => $cid]); | ||||
|         $attchs     = DB::dql( | ||||
|             'select attch from attachment_album_entry entry ' | ||||
|             . 'left join Component\Attachment\Entity\Attachment attch ' | ||||
|                 . 'with entry.attachment_id = attch.id ' | ||||
|             . 'where entry.collection_id = :cid', | ||||
|         $collection        = DB::findOneBy(Collection::class, ['id' => $cid]); | ||||
|         [$attachs, $notes] = DB::dql( | ||||
|             <<<'EOF' | ||||
|                 SELECT attach, notice FROM \Plugin\AttachmentCollections\Entity\AttachmentCollectionEntry AS entry | ||||
|                 LEFT JOIN \Component\Attachment\Entity\Attachment AS attach | ||||
|                     WITH entry.attachment_id = attach.id | ||||
|                 LEFT JOIN \App\Entity\Note AS notice | ||||
|                     WITH entry.note_id = notice.id | ||||
|                 WHERE entry.collection_id = :cid | ||||
|                 EOF, | ||||
|             ['cid' => $cid], | ||||
|         ); | ||||
|         return [ | ||||
|             '_template'   => 'AttachmentCollections/collection.html.twig', | ||||
|             'page_title'  => $collection->getName(), | ||||
|             'attachments' => $attchs, | ||||
|             'attachments' => array_values($attachs), | ||||
|             'bare_notes'  => array_values($notes), | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,12 +6,13 @@ namespace Plugin\AttachmentCollections\Entity; | ||||
| 
 | ||||
| use App\Core\Entity; | ||||
| 
 | ||||
| class CollectionEntry extends Entity | ||||
| class AttachmentCollectionEntry extends Entity | ||||
| { | ||||
|     // These tags are meant to be literally included and will be populated with the appropriate fields, setters and getters by `bin/generate_entity_fields`
 | ||||
|     // {{{ Autocode
 | ||||
|     // @codeCoverageIgnoreStart
 | ||||
|     private int $id; | ||||
|     private int $note_id; | ||||
|     private int $attachment_id; | ||||
|     private int $collection_id; | ||||
| 
 | ||||
| @@ -26,6 +27,17 @@ class CollectionEntry extends Entity | ||||
|         return $this->id; | ||||
|     } | ||||
| 
 | ||||
|     public function setNoteId(int $note_id): self | ||||
|     { | ||||
|         $this->note_id = $note_id; | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     public function getNoteId(): int | ||||
|     { | ||||
|         return $this->note_id; | ||||
|     } | ||||
| 
 | ||||
|     public function setAttachmentId(int $attachment_id): self | ||||
|     { | ||||
|         $this->attachment_id = $attachment_id; | ||||
| @@ -54,11 +66,12 @@ class CollectionEntry extends Entity | ||||
|     public static function schemaDef() | ||||
|     { | ||||
|         return [ | ||||
|             'name'   => 'attachment_album_entry', | ||||
|             'name'   => 'attachment_collection_entry', | ||||
|             'fields' => [ | ||||
|                 'id'            => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'], | ||||
|                 'note_id'       => ['type' => 'int', 'foreign key' => true, 'target' => 'Note.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'foreign key to note table'], | ||||
|                 'attachment_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Attachment.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'foreign key to attachment table'], | ||||
|                 'collection_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'AttachmentCollection.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'foreign key to attachment_collection table'], | ||||
|                 'collection_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Collection.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'foreign key to collection table'], | ||||
|             ], | ||||
|             'primary key' => ['id'], | ||||
|         ]; | ||||
| @@ -13,10 +13,11 @@ | ||||
|     {# Backwards compatibility with hAtom 0.1 #} | ||||
|     <main class="feed" tabindex="0" role="feed"> | ||||
|         <div class="h-feed hfeed notes"> | ||||
|             {% for attachment in attachments %} | ||||
|             {% for key, attachment in attachments %} | ||||
|                 <section class="section-widget section-padding"> | ||||
|                     {% include '/cards/attachments/view.html.twig' with {'attachment': attachment, 'note': null} only%} | ||||
|                     <a class="section-widget-button-like" href="{{ path('attachment_download', {'id': attachment.id}) }}"> {{ 'Download link' | trans }}</a> | ||||
|                     {% include '/cards/attachments/view.html.twig' with {'attachment': attachment, 'note': bare_notes[key], 'title': attachment.getBestTitle(bare_notes[key])} only %} | ||||
|                     <a class="section-widget-button-like" | ||||
|                        href="{{ attachment.getDownloadUrl(bare_notes[key]) }}"> {{ 'Download link' | trans }}</a> | ||||
|                 </section> | ||||
|             {% else %} | ||||
|                 <div id="empty-notes"><h1>{% trans %}No attachments here.{% endtrans %}</h1></div> | ||||
|   | ||||
| @@ -20,23 +20,23 @@ | ||||
|             {% endif %} | ||||
|             <div class="h-entry hentry note attachment-collections-list"> | ||||
|                 <h3>{{ 'Your collections' | trans }}</h3> | ||||
|             {% for col in collections %} | ||||
|                 <div class="attachment-collection-item"> | ||||
|                     <a class="name" href="{{ fn.getUrl(col.id) }}">{{ col.name }}</a> | ||||
|                     <details title="Expand if you want to edit the collection's name"> | ||||
|                         <summary> | ||||
|                             <div class="collection-action">{{ icon('edit') | raw }}</div> | ||||
|                         </summary> | ||||
|                         {{ form(fn.editForm(col)) }} | ||||
|                     </details> | ||||
|                     <details title="Expand if you want to delete the collection"> | ||||
|                         <summary> | ||||
|                             <div class="collection-action">{{ icon('delete') | raw }}</div> | ||||
|                         </summary> | ||||
|                         {{ form(fn.rmForm(col)) }} | ||||
|                     </details> | ||||
|                 </div> | ||||
|             {% endfor %} | ||||
|                 {% for col in collections %} | ||||
|                     <div class="attachment-collection-item"> | ||||
|                         <a class="name" href="{{ fn.getUrl(col.id) }}">{{ col.name }}</a> | ||||
|                         <details title="Expand if you want to edit the collection's name"> | ||||
|                             <summary> | ||||
|                                 <div class="collection-action">{{ icon('edit') | raw }}</div> | ||||
|                             </summary> | ||||
|                             {{ form(fn.editForm(col)) }} | ||||
|                         </details> | ||||
|                         <details title="Expand if you want to delete the collection"> | ||||
|                             <summary> | ||||
|                                 <div class="collection-action">{{ icon('delete') | raw }}</div> | ||||
|                             </summary> | ||||
|                             {{ form(fn.rmForm(col)) }} | ||||
|                         </details> | ||||
|                     </div> | ||||
|                 {% endfor %} | ||||
|             </div> | ||||
|         </div> | ||||
|     </main> | ||||
|   | ||||
| @@ -9,7 +9,8 @@ | ||||
|                 {{ form(add_form) }} | ||||
|             </fieldset> | ||||
|  | ||||
|             <details class="section-widget-subtitle-details section-padding" title="Expand if you want to access more options."> | ||||
|             <details class="section-widget-subtitle-details section-padding" | ||||
|                      title="Expand if you want to access more options."> | ||||
|                 <summary class="section-subtitle-summary"> | ||||
|                     <strong>{% trans %}Other options{% endtrans %}</strong> | ||||
|                     {{ icon('arrow-down', 'icon icon-details-close') | raw }} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user