5.2. Пример добавления сообщения типа «Отчет».

Этот пример демонстритует, как можно устанавливать соединение с базой данных, создавать сообщения и прикладывать файлы без использования графического интерфейса Cerebro. Его можно использовать, например, для создания отчетов из Nuke, Maya и других программных продуктах, в которых возможно исполнение питоновских скриптов.

Пример находится в папке «py_cerebro/examples» серверного модуля.

py_cerebro/examples/report.py

# -*- coding: utf-8 -*-

"""
Пример добавления сообщения типа "Отчет".
Этот модуль демонстритует, как можно устанавливать соединение с базой данных,
создавать сообщения и прикладывать файлы без использования графического интерфейса Cerebro.
Его можно использовать, например, для создания отчетов из Nuke, Maya и других программных продуктах,
в которых возможно исполнение питоновских скриптов.

Модуль использует пакет py_cerebro (для Python 3.x), который входит в дистрибутив service-tools (http://cerebrohq.com/distribs/service-tools.zip).
Пакет py_cerebro содержит модули для установки соединения с базой данных
и для доступа к файловому хранилищу(Cargador).
Пакет py_cerebro использует сторонний пакет psycopg2 (http://initd.org/psycopg/)
для осущевстления доступа к базе данных PostgreSQL. Возможно вам придется дополнительно установить этот пакет.
Psycopg2 поставляется в дистрибутиве для всех операционных систем (папка py-site-packages). Также его можно
скачать с сайта разработчика (http://initd.org/psycopg/).

Модуль содержит функцию add_report_to_task для добавления сообщения с приложенным файлом.

Также, в этом модуле описана функция get_task_and_message_ids - пример получения идентификаторов задачи
и её сообщения типа "Постановка задачи" по локатору(пути) задачи.

Для добавления сообщения необходимо вызвать функцию add_report_to_task
и передать ей необходимые параметры.
"""

import fnmatch
import sys
import os
import subprocess

local_dir = os.path.realpath(__file__).replace('\\', '/').rsplit('/', 1)[0]
backend_dir = local_dir + '/..'
sys.path.append(backend_dir)
backend_dir = local_dir + '/../..'
sys.path.append(backend_dir)

from py_cerebro import dbtypes, database, cargador, cclib # в этом модуле описаны различные константы, такие как поля данных, флаги и т.п.


# Переменные, которые вам возможно придется изменить, чтобы преспособить сктипт для вашей сети
mirada_path = '//ss/front/cerebro/mirada.exe' # Путь, откуда запускать мираду для генерации эскизов.
#У вас этот параметр скорее всего будет иным.

#Следующие два параметра, хост и порт - это наш главный сервер с базой данных.
#У вас эти параметры могут быть иными, если вы используете свою базу данных
database_host = 'cerebrohq.com'
database_port = 45432

cargador_host = 'ss' # Cетевой адрес машины, где работает севрис каргадор.
# Может быть задано сетевое имя или IP адрес. 'ss' - это имя нашего сервера, у вас этот параметр скорее всего будет иным.

cargador_xmlrpc_port = 4040 # Порт 4040 - это порт для запросов по xmlrpc протоколу.
#У вас порт может быть иным, подробнее об этом смотрите в комментариях модуля cargador пакета py-backend.

cargador_http_port = 4080 # Порт 4080 - это порт для запросов по http протоколу.
#У вас порт может быть иным, подробнее об этом смотрите в комментариях модуля cargador пакета py-backend.


def add_report_to_task(task_url, db_user, db_password, text, work_time, file, file_as_link):
        """
        Функция по добавлению нового сообщения.

        Параметр task_url - тектовый локатор(путь) до задачи.

        Формат локатора: '/Проект/Задача 1/Задача 2', то есть по сути путь до задачи.
        Примечание: Имена задач регистрозависимы!

        Параметры db_user и db_password - логин и пароль пользователя Cerebro, который создает отчет.

        Параметр text - текс сообщения
        Параметр work_time - затраченные часы
        Параметр file - путь до файла, который должен быть приложен
        Параметр file_as_link - способ добавления файла к сообщению:
                True - файл добавляется как ссылка;
                False - файл добавляется как вложение, то есть импортируется в файловое хранилище(Cargador).

        Пример вызова функции:
        ::
                import report

                report.add_report_to_task('/Проект/Задача 1/Задача 2', 'user', 'password', 'Example report', 1.5, 'с:/temp/Test.file', False)
        ::
        """

        try:

                db = database.Database(database_host, database_port)
                # Устанавливаем соединение с базой данных
                if db.connect_from_cerebro_client() != 0: # пробуем установить соединение с помощью запущенного клиента Cerebro.
                        # Если не выходит, устанавливаем с помощью логина и пароля
                        db.connect(db_user, db_password)

                # Получение идентификатора задачи и сообщения типа "Постановка задачи" по локатору задачи
                task = db.task_by_url(task_url) # Получили ID задач
                if len(task) == 0 or task[0] == None: # Проверяем существуют ли задачи с таким локатором
                        raise Exception('Задача не найдена')

                messages = db.task_definition(task[0]) # Получили сообщения задачи
                if len(messages) == 0: # Проверяем есть ли у задачи сообщения
                        raise Exception('Сообщение отсутствует')

                parent_message = messages[dbtypes.MESSAGE_DATA_ID] # Получили ID сообщения
                if parent_message == None or parent_message == 0:
                        raise Exception('Сообщение отсутствует')
                """
                Параметры task и parent_message - это идентификаторы задачи и сообщения к которому добавляется новое сообщение.
                """

                # Создание сообщения типа "Отчет"
                new_message_id = db.add_report(task[0], parent_message, text, int(work_time*60))
                """
                Выполняем запрос на добавление нового соообщения.
                Последний параметр, затраченное время, задается в минутах
                Результатом запроса является идентификатор нового сообщения
                """

                # Приложение файла к отчету
                if file != None and len(file) != 0 and os.path.exists(file): # проверяем, задан ли файл, который нужно приложить к отчету

                        # генерация эскизов для файла file
                        thumbnails = make_thumnails(file)
                        """
                        Если файл является изображением или видео, то можно добавить для него уменшенные эскизы.
                        Можно добавить до 3-х эскизов (первый, средний, последний кадры).
                        Для генерации эскизов в этом примере мы будем использовать программу Mirada.
                        Она постовляется вместе с дистрибутивом Cerebro. Можно использовать и другие программы для генерации,
                        например, ffmpeg. Смотрите подробнее об этом в описании функции make_thumnails.
                        """

                        # Создаем объект для добавления файла и/или эскизов в файловое хранилище (Cargador)
                        carga = cargador.Cargador(cargador_host, cargador_xmlrpc_port,  cargador_http_port)
                        """
                        Если файл прикладывается как ссылка, то сам файл не будет
                        """

                        # Добовляем к отчету постановки задач файлы и, заодно, экспортируем их в хранилище
                        db.add_attachment(new_message_id, carga, file, thumbnails,  '',  file_as_link)
                        """
                        Если файл прикладывается как ссылка, то сам файл не будет экспортироваться в хранилище,
                        но будут экспортированы эскизы.

                        Пустая строка - это комментарий к вложению. Можете его задать по желанию.
                        """

        except Exception as err:
                print(err)

def make_thumnails(filename):
        """
        Принимает на вход полный путь до файла видео или изображения и генерирует эскизы к ним
        Возвращает список путей до файлов эскизов.

        Генерация эскизов:
        Если файл является изображением или видео, то можно добавить для него уменшенные эскизы.
        Можно добавить до 3-х эскизов (первый, средний, последний кадры).
        Для генерации эскизов можно использовать программу Mirada.
        Она постовляется вместе с дистрибутивом Cerebro. Можно использовать и другие программы для генерации,
        например, ffmpeg.
        """

        #Пример генерации эскизов с помощью Mirada.

        if os.path.exists(filename) == False or os.path.exists(mirada_path) == False:
                return list()

        gen_path = os.path.dirname(filename) # В качестве директории для генерации эскизов возьмем директорию добавляемого файла

        # Запускаем мираду с необходимыми ключами
        res_code = subprocess.call([mirada_path, filename, '-temp', gen_path, '-hide'])
        #-temp - директория для генерации эскизов
        #-hide - ключ запуска мирады в скрытом режиме (без загрузки графического интерфейса) для генерации табнейлов.

        if res_code != 0:
                raise Exception("Mirada returned bad exit-status.\n" + mirada_path)

        #Ищем сгенерированные мирадой эскизы.
        #Имени эскиза формируется из имени файла, даты и времени генерации - filename_yyyymmdd_hhmmss_thumb[number].jpg
        #Например: test.mov_20120305_112354_thumb1.jpg - первый эскиз видео-файла test.mov

        thumbnails = list()
        for f in os.listdir(gen_path):
                if fnmatch.fnmatch(f, os.path.basename(filename) + '_*_thumb?.jpg'):
                        thumbnails.append(gen_path + '/' + f)

        thumbnails.sort()

        """
        #Пример генерации эскизов с помощью ffmpeg.

        #Для того, чтобы генерить эскизы с помощью ffmpeg, нужно заранее знать длительность видео,
        #чтобы корректно получить средний и последний кадры.
        #Возьмем к примеру ролик длительностью в 30 секунд.

        thumbnails = list() # список файлов для эскизов
        thumbnails.append(filename + '_thumb1.jpg')
        thumbnails.append(filename + '_thumb2.jpg')
        thumbnails.append(filename + '_thumb3.jpg')

        subprocess.call(['ffmpeg', '-i', filename, '-s', '512x512', '-an', '-ss', '00:00:00', '-r', 1, '-vframes', 1, '-y', thumbnails[0]])
        subprocess.call(['ffmpeg', '-i', filename, '-s', '512x512', '-an', '-ss', '15:00:00', '-r', 1, '-vframes', 1, '-y', thumbnails[1]])
        subprocess.call(['ffmpeg', '-i', filename, '-s', '512x512', '-an', '-ss', '30:00:00', '-r', 1, '-vframes', 1, '-y', thumbnails[2]])
        # Описание ключей вы можете посмотреть в документации к ffmpeg
        """

        return thumbnails