[Tickets] Версия 1.4.0-beta4 - Загрузка файлов

Готова новая бета-версия Tickets, в которой можно загружать файлы к тикету. Это очередной пример дружного финансирования разработок, полезных для сообщества, этим самым сообществом.

Кто не видел — вот исходная тема. Начиналось всё довольно безобидно: попросили соединить Uploadify и Tickets. В процессе соединения оказалось, что выходит ерунда, поэтому пришлось делать всё по-полной.

Итого, я провозился аж 4 дня, вместо 1 запланированного. Но результат того стоит:
Подробности под катом.

Логика работы

Все файлы загружаются сразу при добавлении и сохраняются в новую таблицу TicketFile. В зависимости от типа файла (картинка или нет), генерируется уменьшенная копия и сохраняется в поле thumb.

Правила загрузки и генерации превью, как обычно, прописаны в источнике медиа. Стандартный для Tickets устанавливается вместе с обновлением. Обратите внимание: в отличии от MS2 всегда генерируется только одна превьюшка, поэтому формат JSON массива немного другой.

Сразу после загрузки файлам присваивается пользователь-владелец и нулевой документ-родитель. Пока вы не сохраните тикет вместе с загруженным файлом — он считается новым и показывается вам в окошке создания и редактирования тикета.

Если картинка вам не нужна — её можно удалить, вернее, поставить флаг deleted. Физически же файл и запись в БД будут удалены при обновлении формы (только для новых файлов) или при сохранении тикета (для всех).

То есть, файл еще не привязанный к тикету удаляется проще, чем привязанный. Сама привязка происходит при сохранении тикета. Пока вы его не сохраните — файл болтается неприкаянный и показывается вам в форме тикета.

Удаляемый тикеты обводятся красной рамкой, новые — синей. Все стили, как обычно, в default.css.

Новые параметры сниппета TicketForm:
  • allowFiles — Разрешить загрузку файлов? Если да — то подключится загрузчик и нужные скрипты.
  • source — Источник медиа-файлов, в который будут сохранены изображения. По умолчанию берется системны настройка tickets.source_default, в которую прописывается источник Tickets Files.
  • tplFiles — Чанк-обертка всего блока работы с файлами. Загружчик, список файлов и прогрессбар.
  • tplFile — Чанк оформление файла, который не является изображением.
  • tplImage — Чанк офомрления картинок.
Советую зайти в источник файлов и вдумчиво почитать описания фиолетовых параметров — они влияют на работу загрузчика и сохранение файлов.

Да, старый баг с несохранением этих фиолтеовых параметров при открытии в окошке никуда не делся. Используйте быстрое редактирование двойным кликом на значении.

Загрузчик

Непосредственно загрузкой файлов занимается мега-скрипт Plupload, который работает везде, умеет drug & drop, ресайз на клиенте и еще много чего.

В частности, он не позволит вам загрузить слишком большой файл, проверяя его размер при добавлении. Огромные картинки будут отресайзены до значений, указанных в источнике файлов также — прямо у вас на компе, еще до загрузки на сервер.


Также на клиенте будет проверено расширение файла, а в окне выборе будут активны только разрешенные типы.

Контроль целостности

Ссылку на загруженный файл можно сразу вставить в тикет — пока он не сохранен путь у картинок будет такой:
/assets/images/tickets/0/имяфайла.png
/assets/images/tickets/0/имяфайла_thumb.jpg
Обратите внимание, что путь указывает на нулевой ресурс. При сохранении этот путь заменится на реальный id документа.

Если вы удаляете файл, но оставляете ссылку на него в документе — она тоже будет удалена при сохранении тикета. Таким образом, битых ссылок быть не должно. Проверяются content и introtext.

Физический перенос файла в новую директорию прописан в методе TicketFile::save() и срабатывает при смене родителя.

Вывод загруженных файлов

Выводом загруженных файлов посетителям занимается сниппет TicketMeta. У него появились новые параметры, и по умолчанию он показывает только те файлы, ссылки на которые отсутствуют в контенте тикета.
  • getFiles — Выводить список загруженных файлов?
  • tplFile — Чанк оформления сслыки на файл.
  • unusedFiles — Выводить только файлы, неиспользованные в контенте документа.
Обертка для вывода файлов прописана в чанке tpl.Tickets.meta, в быстром плейсхолдере has_files.

Понятное дело, что файлы можно выводить и при помощи pdoResources:
[[!pdoResources?
	&class=`TicketFile`
	&where=`{"parent":16}`
	&sortby=`createdon`
	&sortdir=`ASC`
]]
Сортировку нужно указать обязательно, иначе сниппет попытается сортировать по колонке publishedon, которая у TicketFile отсутствует.

Заключение

Вот и появился у нас компонент, который умеет создавать страницы с фронтенда, комментировать, голосовать и даже загружать файлы.

Кстати говоря, в этой версии исправлена еще пара ошибок и добавлена мега-фича: сниппет TicketMeta теперь можно вызывать на любых ресурсах. Да, и голосовать за них теперь тоже можно, и количество комментариев для них он тоже выводит, и просмотры.

Напоминаю, что это по-прежнему бета-версия, которую нужно тестировать. Учитывая, что используется Plupload, загрузка должны работать везде, даже на HTML4, а вот отсутствие глюков в php я вам не обещаю. Свой сайт я пока не обновляю, скорее всего, новый Tickets будет использоваться уже сразу на modx.pro.

При обновлении советую обратить внимание на чанки:
  • tpl.Tickets.form.create
  • tpl.Tickets.form.update
  • tpl.Tickets.meta
Они были изменены и их нужно обновить при установке, или вручную из репозитория.

Все желающие поддержать проделанную работу могут сказать спасибо материально или вербально, в комментариях.

Следующая заметка
[Sendex] Версия 1.0.0-pl — Отправка нескольких писем вручную
Предыдущая заметка
[Tickets] Версия 1.4.0-beta - Настройки секции


Комментарии ()

  1. Чикин Артур 25 марта 2014, 18:32 # 0
    Спасибо.
    1. Александр Наумов 25 марта 2014, 21:19 # 0
      Спасибо!!!
      1. Андрей 25 марта 2014, 21:20 # 0
        Здравствуйте Василий!
        Ссылка
        <span class="col-md-2"><a href="[[~[[+section.id]]]]"><i class="glyphicon glyphicon-folder-open"></i> [[+section.pagetitle]]</a></span>
        в чанке tpl.Tickets.meta почему-то отправляет меня на главную страницу сайта
        1. Василий Наумкин 25 марта 2014, 21:42 # 0
          Поправил, обновись.
          1. Андрей 25 марта 2014, 21:46 # 0
            Ок, спасибо!
        2. Clean 25 марта 2014, 22:34 # +2
          Василий, возможности потестировать твою мегафичу сейчас нет, но по тексту
          смотри
          Ссылку на загруженный файл можно сразу вставить в тикет — пока он не сохранен путь у картинок будет такой:
          /assets/images/tickets/0/имяфайла.png
          /assets/images/tickets/0/имяфайла_thumb.jpg
          Мне кажется произойдет факап, если в один момент два пользователя из под разных сессий загрузят файл с одним и тем же именем? Я так понимаю победит тот, кто загрузит файл последним… Возможно есть смысл расширить путь например до ID юзера:
          /assets/images/tickets/0/[[+modx.user.id]]/имяфайла.png
          1. Rоман Роман 26 марта 2014, 03:45 # +1
            у меня есть одно нуууочень кастомное решение на Revo, когда прикручивал к нему BlueImp Fileupload, несохраненные фотографии складывал в /assets/images/номер_объявления/temp/, а при сохранении phpthumb рендерил их в /assets/images/номер_объявления/ с префиксами «1_» «2_» и «3_». А имена файлов потом кучей в JSON и так далее
            1. Василий Наумкин 26 марта 2014, 08:12 # 0
              Да ты прав, только это не помешает юзеру перезаписать свой же файл.
              То есть, создал тикет, загрузил туда «image.jpg», а через пару дней загружаешь другой «image.jpg» — содержимое у них разное, а имена одинаковые и один затрёт другой, что может быть неприятным сюрпризом — ты же не помнишь, что загружал в прошлый раз?

              Так что добавлю проверку не только по содержимому, но и по имени. Если такое имя уже есть в нулевой директории или в директории тикета — будет ошибка, переименовывай перед загрузкой.
              Ну и по умолчанию лучше включить не-friendly имена картинок в настройках media source.
              1. Алексей Карташов 26 марта 2014, 11:54 # +1
                А не проще вместо имени юзера использовать session_id()? Уж это значение точно у каждого посетителя уникально. К тому же можно точный «сборщик мусора» сделать — по крону в нулевой папке чистить изображения с несуществующими в базе id сессий.
                1. Чикин Артур 26 марта 2014, 11:57 # 0
                  Так то в базе тоже сессии переодически чистятся.
                  1. Василий Наумкин 26 марта 2014, 12:19 # 0
                    Чем проще? Авторизовался из другого браузера — другой session_id().

                    Вопрос уже решен проверкой имени файла и его содержимого при загрузке.
                    1. Чикин Артур 26 марта 2014, 14:34 # 0
                      Переименовывать картинку в ее хеш это тоже не подходит?
                      1. Василий Наумкин 26 марта 2014, 14:38 # 0
                        Зачем помогать человеку загрузить 2 файла с одинаковым именем или содержимым?

                        Ну вот реально, зачем? Чтобы на странице было 2 файла с одинаковым именем, или чтобы было 2 одинаковых картинки?
                        1. Чикин Артур 26 марта 2014, 17:46 # 0
                          разве если просто посчитать md5 файла то у 2 одинаковых файлов он будет разный?
                          1. Clean 27 марта 2014, 00:37 # 0
                            Хэш от одного и того-же входного параметра, всегда одинаков.
                  2. Максим Франц 26 марта 2014, 12:51 # 0
                    будет ошибка, переименовывай перед загрузкой
                    Не совсем юзер френдли получится. Индексы не вариант?
                    image.jpg image(1).jpg image(2).jpg
                    1. Василий Наумкин 26 марта 2014, 12:54 # 0
                      Присылай свою реализацию на github — посмотрю.
                      1. Максим Франц 26 марта 2014, 13:01 # 0
                        Котерова дочитаю — возможно…
                    2. Andrei Kilin 31 марта 2014, 22:49 # 0
                      Салют!

                      А не упростит ли задачу, если создание тикета разбить на 2 этапа?
                      1. Пользователь вводит только название тикета, выбирает секцию и тыкает на «продолжить».
                      2. Тут создается неопубликованный тикет и сразу перекидывает на его редактирование, где уже все плюшки есть: поле редактора, картинки, публикация и прочее.

                      м?
                  3. Николай 25 марта 2014, 22:56 # +7
                    И после вот такого, находятся умники кричащие какое это плохое сообщество с зазнавшимся автором.
                    Рад был бы лично, Василий пожать тебе руку за подобные труды! Жаль географическое положение не позволяет.
                    1. Александр Котлов 26 марта 2014, 01:03 # 0
                      Спасибо!
                      1. Константин Кононов 26 марта 2014, 09:13 # 0
                        Спасибо огромное!
                        1. Илья 26 марта 2014, 10:55 # 0
                          Огромное спасибо!
                          А реально demo.modx.pro/tickets обновить, чтобы в живую поюзать, перед глобальным обновлением?
                            1. Володя 26 марта 2014, 14:38 # 0
                              Кулл!!! Молодчик )))
                              p.s. Василий случайно сюда зашел — demo.modx.pro/minishop2
                              Вроде ссылок на сравнение нет…
                              1. Василий Наумкин 26 марта 2014, 14:43 # 0
                                Спасибо, поправил.

                                Обновил MS2 с перезаписью чанков =)
                              2. Станислав 01 апреля 2014, 20:21 # 0
                                Василий, вчера все прекрасно работало, а сегодня пишет — Доступ запрещен. На демо такое же поведение. Начинает работает если в tickets.class.php в config дописать 'allowFiles','source','tplImage','tplFile'.
                                1. Василий Наумкин 01 апреля 2014, 20:27 # 0
                                  Поправил, обновись.
                                  1. Станислав 01 апреля 2014, 21:28 # 0
                                    тоже и для «Удалить»
                                    1. Василий Наумкин 02 апреля 2014, 05:36 # 0
                                      Еще раз поправил, можно обновляться.
                            2. Иван Брежнев 26 марта 2014, 16:41 # 0

                              Firefox 28.0
                              1. Павел Левин 26 марта 2014, 18:25 # 0
                                Читай я длинный пост (с учетом комментов) на зачатках идеи, зашел… результат удивил).
                                Сам не пользуюсь этим, но Василий молодец и все кто собрались и скинулись.
                                1. Clean 27 марта 2014, 00:39 # +1
                                  Хочется верить что после полировки этой доработки, следующей будет bezumkin.ru/sections/work/2586/, при таких раскладах MODx получит практически максимальный функционал для фронт-енд использования.
                                  1. Наумов Алексей 27 марта 2014, 16:17 # 0
                                    Раз такая пьянка, может надо сделать и прикрепление файлов (изображений) к комментариям? )))
                                    Например так: fishspace.ru/places/to/kireevskij/gamovo/

                                    Думаю что у комментария нет смысла вставлять изображение в текст. Просто список прикрепленных файлов должен идти после комментария.
                                    1. Иван Брежнев 27 марта 2014, 16:28 # 0
                                      А я считаю что это нормально вставлять изображения в текст комментария, кто будет открывать эти вложения?
                                      1. Чикин Артур 28 марта 2014, 08:27 # 0
                                        Зависит от цели которую ты преследуешь.
                                        1. Иван Брежнев 28 марта 2014, 08:32 # 0
                                          скорее всего
                                        2. Наумов Алексей 28 марта 2014, 09:53 # 0
                                          я наверное погорячился с вложениями. Тут кому как удобнее видимо. Для меня вложения. Т.к. мои пользователи в компьютерах не очень, и ими проще прикрепить, как в почте, чем вставлять в текст.
                                          1. Иван Брежнев 28 марта 2014, 09:56 # 0
                                            Тогда нужно делать для вашей целевой аудитории и так как им будет проще и доступнее
                                        3. Василий Наумкин 27 марта 2014, 16:30 # 0
                                          Нагрузка на отрисовку ветки комментариев может прилично так вырасти.

                                          Но на уровне БД и общей логики я такой вариант предусмотрел — возможно когда-нибудь сделаю, опционально.
                                          1. Чикин Артур 28 марта 2014, 08:12 # 0
                                            Ajax подгрузка картинок при скроле в низ? Таких микро плагинов для jQuery помойка вроде как.
                                            1. Василий Наумкин 28 марта 2014, 08:14 # 0
                                              Ну тогда жду от тебя реализации на github.

                                              Все всё знают и умеют, кроме меня — так давайте делать уже.
                                              1. Rоман Роман 30 марта 2014, 23:00 # 0
                                                В ЖЖ по-другому же сделано: открыты 2 первых комментария в ветке, а что дальше идет в треде — подгружается по запросу, и открывает только текущий тред
                                                1. Василий Наумкин 30 марта 2014, 23:04 # 0
                                                  Лично мне это совершенно не нравится.
                                        4. Давид Мовсесян 27 марта 2014, 16:56 # 0
                                          Может не в тему, в настройках секции тикетов не запоминается настройка секции «Выполнять теги MODX»
                                          1. Дмитрий Куликов 28 марта 2014, 11:37 # 0
                                            Вопрос: как вывести только те тикеты, к которым нет комментариев?.. Понимаю нужно написать, условие вроде &where=`[{«comments»:[0]]}` Но не совсем понимаю как правильно его написать. Помогите пожалуйста!
                                            1. Василий Наумкин 28 марта 2014, 12:00 # 0
                                              Как работает SQL представляешь?
                                              Понятно ли, что тикеты — это одна таблица, а комментарии — другая? Нужно как минимум сделать join этих таблиц, чтобы задавать условия для выборки.
                                              1. Дмитрий Куликов 28 марта 2014, 14:36 # 0
                                                Недавно начал разбираться с SQL. Т, е. мне прямо в условии where нужно построить sql запрос который выберет все тикеты, у которых есть комментарии?
                                                1. Rоман Роман 30 марта 2014, 23:02 # 0
                                                  Вот как примерно-приблизительно разберешься с SQL, примерно-приблизительно разберись с PDO и XPDO запросами в Revo. Вот честно, по-другому ничего не поймешь
                                                  1. Дмитрий Куликов 31 марта 2014, 09:57 # 0
                                                    Спасибо, буду осваиваться! Пока решил вот так
                                            2. Наумов Алексей 05 апреля 2014, 07:38 # 0
                                              Василий, добрый день!

                                              Вчера обновился до свежей версии тикетс, что-бы воспользоваться всеми новыми плюшками. Но сразу же выплыло неудобство: создается только 1 превью для загруженного файла. Причем мне нужно превью большого размера, 400 точек в ширину, а высоту любое, но с ограничением до 1000 допустим. Ок, пропишу в источниках файлов, но тогда сломается предпросмотр превьюшек при создании поста. В чем сложность сделать возможность создания нескольких превью? Пусть они бы были записаны в виде
                                              [
                                              {"thumb": "w=120&h=90&..."},
                                              {"anotherthumb": "w=400&h=1000&..."},
                                              ]
                                              и в разных случаях мы бы просто использовали разный ключ. Или оставить текущую настройку thumbnail и добавить к ней дополнительно еще настройку thumbnails с массивом, как в gallery. В этом случае, изображения вставлять не полным кодом в текст, а так:
                                              <img src="1" />
                                              — где 1 — порядковый номер изображения у данного тикета. А про отображении уже заменять на то, что хочется. На превью, превью со ссылкой, ну в общем как пожелает пользователь.

                                              Если это возможно сделать, готов проспонсировать.
                                              1. Василий Наумкин 05 апреля 2014, 08:10 # 0
                                                Ты даже не представляешь, насколько я устал от всех этих «в чем сложность сделать возможность...». Бери — да делай, исходники открыты.

                                                Если нет желания — используй phpthumbof или phpthumbon.
                                                1. Наумов Алексей 05 апреля 2014, 08:38 # 0
                                                  да понимаю, пытаюсь свои идеи рассказать, которые возникли после применения на практике. Костыль городить не хочется, но сгорожу уж, не проблема.
                                              2. Борис И 20 апреля 2014, 11:45 # 0
                                                Василий, здравствуйте. Большое спасибо за превосходный компонент.
                                                Подскажите пожалуйста, хочу сделать водяные знаки, при загрузке с фронта, на картинки (превью и увеличенную). С превью, проблем нет, в источнике выставляю
                                                {"w":720,"h":400,"q":90,"zc":"1","bg":"000000","fltr":"wmt|site.ru|20|BR|DDEDF7|7fonts.ru_GAU_root_N.TTF|90|20|5||0|"}
                                                и все в порядке.
                                                Для того, чтобы сделать водяные знаки на увеличенном изображении пытаюсь использовать phpthumbon (саму картину оригинал не трогаю). Для этого в чанке tpl.Tickets.form.image вместо [[+url]] (ссылки на оригинал) прописываю
                                                [[phpthumbon? &phpthumbon.cache_dir=`images` &options=`fltr[]=wmt|site.ru|40|BR|DDEDF7|/core/model/phpthumb/fonts/7fonts.ru_GAU_root_N.TTF|90|20|5|0|0|` &input=`[[+url]]` ]]
                                                до очистки кэша все в порядке, а после и превью исчезает.
                                                Посмотрел, у картинок (превью и увеличенной) в созданном тикете остаются пути на /assets/images/tickets/0/… не происходит замены на id ресурса. Причем, увеличенная картинка открывается, даже после очистки кэша и с путем /assets/images/tickets/0/…
                                                Прошу прошения если объяснил непонятно, осваиваю modx. Подскажите, куда копать.
                                                1. Василий Наумкин 20 апреля 2014, 17:50 # 0
                                                  Посмотрел, у картинок (превью и увеличенной) в созданном тикете остаются пути на /assets/images/tickets/0/… не происходит замены на id ресурса. Причем, увеличенная картинка открывается, даже после очистки кэша и с путем /assets/images/tickets/0/
                                                  А версия точно последняя? Я вроде это уже починил.
                                                  1. Борис И 20 апреля 2014, 19:18 # 0
                                                    Василий, спасибо. Пришлось обновить вручную, автоматом почему то показывало, что последняя версия. Превью стали открываться нормально, id присваивается.
                                                    Потестил немного phpthumbon, для создания увеличенной картинки, чувствую, в дальнейшем, с ним могут возникнуть проблемы, естественно он не меняет /assets/images/tickets/0/ на id (а значит может перезаписать картинки). Чтобы не затирались картинки дополнил его параметром
                                                    &phpthumbon.cache_dir=`images/[[+id]]`
                                                    , получилась интересная штука. Пример: к превью картинки путь /assets/images/tickets/103/ и id ресурса соответственно 103. А у phpthumbon путь получился /assets/images/110/tickets/0/ (откуда взялось 110, вместо 103, загадка). При создании следующего ресурса будет 104 и 111.
                                                    В общем криво получается. Как бы боком не вышла защита увеличенных картинок ватермаркой.
                                                2. Николай Загумённов 03 мая 2014, 17:57 # 0
                                                  Никак не могу найти где менять миниатюры изображений. Как вот тут показано:

                                                  В настройках системы нет. Не подскажете где эти настройки?
                                                  1. Дмитрий Кондаков 04 мая 2014, 09:52 # 0
                                                    Инструменты > Источники файлов
                                                    1. Николай Загумённов 04 мая 2014, 09:59 # 0
                                                      спасибо!
                                                  2. Тимофей 01 декабря 2014, 00:12 # 0
                                                    Подскажите, после нажатия кнопки
                                                    <input type="button" class="btn btn-primary publish" name="publish" value="Опубликовать" title="" />
                                                    — куда передаются параметры? Внутрь сниппета TicketForm или куда-нибудь в другое место?
                                                    Добавление новых комментариев отключено.