Исходный код py_cerebro.database

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

"""
Модуль py_cerebro.database содержит описание классов, используемых для осуществления доступа к базе данных.

.. rubric:: Классы

* :py:class:`py_cerebro.database.Database`
"""

import os
import re
import socket
import struct
import postgresql # модуль доступа к базе данных postgresql
from .cclib import *
from .dbtypes import *



[документация]class Database(): """ :param string db_host: имя хоста. :param int db_port: порт. :param int db_timeout: таймаут на отключение от базы данных (секунды). :param int db_reconn_count: количество попыток пересоединения. Класс Database предназначен для установления соединения с базой данных, содержит набор методов, выполненяющих стандартные запросы системы Cerebro, а также возможность выполнения произвольных SQL-запросов. :: # Устанавливаем соединение с базой данных if db.connect_from_cerebro_client() != 0: # Пробуем установить соединение с помощью запущенного клиента Cerebro. # Если не выходит, устанавливаем соединение с помощью логина и пароля db.connect('user', 'password') .. note:: В классе существуют функции изменяющие свойства задач, которые могут принимать на вход массив идентификаторов. Если необходимо установить нескольким задачам одинаковое значение свойства, предпочитайте использовать передачу массива идентификаторов в качестве аргумента вместо использования циклов. Это значительно повысит производительность. :: # Использование массивов идентификаторов to_do_task_list = db.to_do_task_list(db.current_user_id(), True) # получаем список задач текущего пользователя tsks = set() for task in to_do_task_list: tsks.add(task[dbtypes.TASK_DATA_ID]) db.task_set_priority(tsks, dbtypes.TASK_PRIORITY_ABOVE_NORMAL) # установили сразу нескольким задачам приоритет выше обычного .. rubric:: Методы * :py:meth:`activities() <py_cerebro.database.Database.activities>` * :py:meth:`add_attachment() <py_cerebro.database.Database.add_attachment>` * :py:meth:`add_client_review() <py_cerebro.database.Database.add_client_review>` * :py:meth:`add_definition() <py_cerebro.database.Database.add_definition>` * :py:meth:`add_note() <py_cerebro.database.Database.add_note>` * :py:meth:`add_report() <py_cerebro.database.Database.add_report>` * :py:meth:`add_resource_report() <py_cerebro.database.Database.add_resource_report>` * :py:meth:`add_review() <py_cerebro.database.Database.add_review>` * :py:meth:`add_task() <py_cerebro.database.Database.add_task>` * :py:meth:`attachment_hashtags() <py_cerebro.database.Database.attachment_hashtags>` * :py:meth:`attachment_remove_hashtags() <py_cerebro.database.Database.attachment_remove_hashtags>` * :py:meth:`attachment_set_hashtags() <py_cerebro.database.Database.attachment_set_hashtags>` * :py:meth:`connect() <py_cerebro.database.Database.connect>` * :py:meth:`connect_from_cerebro_client() <py_cerebro.database.Database.connect_from_cerebro_client>` * :py:meth:`copy_tasks() <py_cerebro.database.Database.copy_tasks>` * :py:meth:`current_user_id() <py_cerebro.database.Database.current_user_id>` * :py:meth:`drop_link_tasks() <py_cerebro.database.Database.drop_link_tasks>` * :py:meth:`execute() <py_cerebro.database.Database.execute>` * :py:meth:`message() <py_cerebro.database.Database.message>` * :py:meth:`message_attachments() <py_cerebro.database.Database.message_attachments>` * :py:meth:`message_hashtags() <py_cerebro.database.Database.message_hashtags>` * :py:meth:`message_remove_hashtags() <py_cerebro.database.Database.message_remove_hashtags>` * :py:meth:`message_set_hashtags() <py_cerebro.database.Database.message_set_hashtags>` * :py:meth:`messages() <py_cerebro.database.Database.messages>` * :py:meth:`project_tags() <py_cerebro.database.Database.project_tags>` * :py:meth:`root_tasks() <py_cerebro.database.Database.root_tasks>` * :py:meth:`set_link_tasks() <py_cerebro.database.Database.set_link_tasks>` * :py:meth:`statuses() <py_cerebro.database.Database.statuses>` * :py:meth:`tag_enums() <py_cerebro.database.Database.tag_enums>` * :py:meth:`task() <py_cerebro.database.Database.task>` * :py:meth:`task_allocated() <py_cerebro.database.Database.task_allocated>` * :py:meth:`task_attachments() <py_cerebro.database.Database.task_attachments>` * :py:meth:`task_by_url() <py_cerebro.database.Database.task_by_url>` * :py:meth:`task_children() <py_cerebro.database.Database.task_children>` * :py:meth:`task_definition() <py_cerebro.database.Database.task_definition>` * :py:meth:`task_hashtags() <py_cerebro.database.Database.task_hashtags>` * :py:meth:`task_links() <py_cerebro.database.Database.task_links>` * :py:meth:`task_messages() <py_cerebro.database.Database.task_messages>` * :py:meth:`task_possible_statuses() <py_cerebro.database.Database.task_possible_statuses>` * :py:meth:`task_remove_allocated() <py_cerebro.database.Database.task_remove_allocated>` * :py:meth:`task_remove_hashtags() <py_cerebro.database.Database.task_remove_hashtags>` * :py:meth:`task_set_activity() <py_cerebro.database.Database.task_set_activity>` * :py:meth:`task_set_allocated() <py_cerebro.database.Database.task_set_allocated>` * :py:meth:`task_set_budget() <py_cerebro.database.Database.task_set_budget>` * :py:meth:`task_set_finish() <py_cerebro.database.Database.task_set_finish>` * :py:meth:`task_set_flag() <py_cerebro.database.Database.task_set_flag>` * :py:meth:`task_set_hashtags() <py_cerebro.database.Database.task_set_hashtags>` * :py:meth:`task_set_name() <py_cerebro.database.Database.task_set_name>` * :py:meth:`task_set_planned_time() <py_cerebro.database.Database.task_set_planned_time>` * :py:meth:`task_set_priority() <py_cerebro.database.Database.task_set_priority>` * :py:meth:`task_set_progress() <py_cerebro.database.Database.task_set_progress>` * :py:meth:`task_set_start() <py_cerebro.database.Database.task_set_start>` * :py:meth:`task_set_status() <py_cerebro.database.Database.task_set_status>` * :py:meth:`task_set_tag_enum() <py_cerebro.database.Database.task_set_tag_enum>` * :py:meth:`task_set_tag_float() <py_cerebro.database.Database.task_set_tag_float>` * :py:meth:`task_set_tag_int() <py_cerebro.database.Database.task_set_tag_int>` * :py:meth:`task_set_tag_string() <py_cerebro.database.Database.task_set_tag_string>` * :py:meth:`task_tag_enums() <py_cerebro.database.Database.task_tag_enums>` * :py:meth:`task_tag_reset() <py_cerebro.database.Database.task_tag_reset>` * :py:meth:`task_tags() <py_cerebro.database.Database.task_tags>` * :py:meth:`tasks() <py_cerebro.database.Database.tasks>` * :py:meth:`to_do_task_list() <py_cerebro.database.Database.to_do_task_list>` * :py:meth:`users() <py_cerebro.database.Database.users>` """ def __init__(self, db_host, db_port, db_timeout = 5, db_reconn_count = 3): """ :param string db_host: имя хоста. :param int db_port: порт. :param int db_timeout: таймаут на отключение от базы данных (секунды). :param int db_reconn_count: количество попыток пересоединения. Конструктор. Пример:: db = database.Database('cerebrohq.com', 45432) """ self.db_url = 'pq://sa_web:web@{0}:{1}/memoria'.format(db_host, db_port) #Строка адреса для установления соединения с базой данных memoria. #Обратите внимание, что для соединение с базой данных memoria происходит их под пользователя sa_web. #Авторизация пользователя производится уже после установки соединения self.db = None self.sid = -1 self.__prepared_statements = dict() # Словарь подготовленных операторов
[документация] def connect(self, db_user, db_password): """ :param string db_user: имя пользователя. :param string db_password: пароль пользователя. Соединение с базой данных с авторизацией. .. seealso:: :py:meth:`connect_from_cerebro_client() <py_cerebro.database.Database.connect_from_cerebro_client>`. """ self.db = postgresql.open(self.db_url) # Устанавливаем соединение qsid = self.db.prepare('select "webStart"($1, $2)') # Подготавливаем запрос для авторизации пользователя rsid = qsid(db_user, db_password) # Выполняем запрос на авторизацию пользователя. self.sid = rsid[0][0] # В качестве результата получаем идентификатор авторизованного пользователя. if(self.sid==-1): raise Exception('Login is invalid'); #self.db->attr_set( 'object_mode' => 0 ); self.qresume = self.db.prepare('select "webResume2"($1::bigint)') # Подготавливаем запрос для подтверждения авторизованного пользователя
[документация] def connect_from_cerebro_client(self): """ Соединение с базой данных с уже авторизованным пользователем в клиенте Cerebro. Такое соединения возможно, если на том же комьютере уже запущен клиент Cerebro, и произведен вход. В этом случае произойдет соединение с базой данных из-под пользователя, вошедшего в клиент. При этом соединение в клиенте не прервется, в отличие от обычного соединения Database.connect по логину и паролю, которое прервет установленное соединение из-под того же пользователя в клиенте. :returns: статус соединения: * 0 - соединение установлено; * 1 - соединение не установлено (клиент Cerebro запущен, но не произведен вход); * 2 - соединение не установлено (клиент Cerebro не запущен). :: # Устанавливаем соединение с базой данных if db.connect_from_cerebro_client() != 0: # Пробуем установить соединение с помощью запущенного клиента Cerebro. # Если не выходит, устанавливаем соединение с помощью логина и пароля db.connect(db_user, db_password) .. seealso:: :py:meth:`connect() <py_cerebro.database.Database.connect>`. """ status = 2 try: cerebro_port = 51051 conn = socket.create_connection(('127.0.0.1', cerebro_port),) proto_version =2 packet_type = 5 msg = struct.pack('II', proto_version, packet_type) header = struct.pack('II', 0xEEEEFF01, len(msg)) conn.send(header+msg) data = conn.recv(1024) res = struct.unpack('IIQ', data) if res[0] == 0xEEEEFF01: session_id = res[2] if session_id == 0: status = 1 else: status = 0 self.db = postgresql.open(self.db_url) # Устанавливаем соединение self.sid = session_id # устанавливаем идентификатор авторизованного пользователя. self.qresume = self.db.prepare('select "webResume2"($1::bigint)') # Подготавливаем запрос для подтверждения авторизованного пользователя conn.close() except Exception as err: #print('Connect to Cerebro', err) pass return status
[документация] def execute(self, query, *parameters): """ :param string query: текст запроса. :param parameters: список параметров запроса. Выполняет запрос и возвращает результат. Результат представлен в виде таблицы (списoк кортежей). """ q = None # Смотрим если ли уже подготовленный оператор if query in self.__prepared_statements: q = self.__prepared_statements.get(query) else: # если нет, подготавлеваеам новый оператор q = self.__prepared_statements.setdefault(query, self.db.prepare(query)) with self.db.xact(isolation='READ COMMITTED'): #'SERIALIZABLE'): self.qresume(self.sid) # Выполняем запрос на подтверждение авторизации пользователя res = q(*parameters) # Выполняем запрос и возвращаем результат return res
[документация] def current_user_id(self): """ :returns: идентификатор пользователя, из-под которого произошёл логин. """ user_id = self.execute('select get_usid()') if len(user_id) == 1: return user_id[0][0] return None
[документация] def root_tasks(self): """ :returns: таблица корневых задач. Поля таблицы описаны в модуле dbtypes: :py:const:`TASK_DATA_...<py_cerebro.dbtypes.TASK_DATA_>` """ tasks = self.execute('select uid from "_task_list_00"(0,0)') ids = set() for task in tasks: ids.add(task[0]) return self.execute('select * from "taskQuery_11"($1)', ids)
[документация] def to_do_task_list(self, user_id, with_done_task): """ :param user_id - идентификатор пользователя или массив идентификаторов пользователей (материального ресурса) :type user_id: int, set(int, ) или list(int, ) :param bool with_done_task: если равен True, то возвратится список вместе с выполненными (прогресс 100%) задачами, иначе без них. :returns: таблица задач, на которых пользователь назначен исполнителем. Поля таблицы описаны в модуле dbtypes: :py:const:`TASK_DATA_...<py_cerebro.dbtypes.TASK_DATA_>` """ tasks = self.execute('select uid from "taskAssigned_byUsers"($1, $2)', {user_id,}, with_done_task) ids = set() for task in tasks: ids.add(task[0]) return self.execute('select * from "taskQuery_11"($1)', ids)
[документация] def task(self, task_id): """ :param int task_id: идентификатор задачи. :returns: данные по задаче. Поля таблицы описаны в модуле dbtypes: :py:const:`TASK_DATA_...<py_cerebro.dbtypes.TASK_DATA_>` .. seealso:: :py:meth:`tasks() <py_cerebro.database.Database.tasks>`. """ task = self.execute('select * from "taskQuery_11"($1)', {task_id,}) if len(task) == 1: return task[0] return None
[документация] def tasks(self, task_ids): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :returns: данные по задаче(задачам). Поля таблицы описаны в модуле dbtypes: :py:const:`TASK_DATA_...<py_cerebro.dbtypes.TASK_DATA_>` .. seealso:: :py:meth:`task() <py_cerebro.database.Database.task>`. """
[документация] def copy_tasks(self, task_id, tasks_list, \ flags = COPY_TASKS_SUB_TASKS|COPY_TASKS_INTERNAL_LINKS|COPY_TASKS_TAGS|COPY_TASKS_ASSIGNED_USERS|COPY_TASKS_EVENTS): """ :param task_id: идентификатор задачи в которую вставляются скопированные задачи. :type task_id: int, set(int, ) или list(int, ) :param set tasks_list: список кортежей типа [(id1, name1), (id2, name2),]. :param int flags: флаги копирования. :returns: список идентификаторов новых задач. Копирует задачи. Подробное описание флагов находится в модуле dbtypes: :py:const:`COPY_TASKS_...<py_cerebro.dbtypes.COPY_TASKS_>` Если одну задачу нужно скопировать несколько раз (реплицировать), то необходимо передать в tasks_list список кортежей с одинаковыми идентификаторами и разными именами. Например: [(123, 'test_task02'), (123, 'test_task03'), (123, 'test_task04'), (123, 'test_task05')] 123 - идентификатор задачи, которую нужно скопировать. 'test_task02', 'test_task03', ... - имена новых задач. :: # Копируем в задачу 0 задачи 1(2 копии), 2 и 3 to_do_task_list = db.to_do_task_list(db.current_user_id(), True) lst_copy = [(to_do_task_list[1][dbtypes.TASK_DATA_ID], 'Копия задачи 1(1)'), (to_do_task_list[1][dbtypes.TASK_DATA_ID], 'Копия задачи 1(2)'), (to_do_task_list[2][dbtypes.TASK_DATA_ID], 'Копия задачи 2'), (to_do_task_list[3][dbtypes.TASK_DATA_ID], 'Копия задачи 3')] db.copy_tasks(to_do_task_list[0][dbtypes.TASK_DATA_ID], lst_copy) # В задачу 0 добавлено 4 новых задачи """ tids = [] names = [] for task_list_id, task_list_name in tasks_list: tids.append(task_list_id) names.append(task_list_name) tasks = self.execute('select "dupVTask"(%s,%s,%s,%s)', tids, names, task_id, flags) ids = set() for task in tasks: ids.add(task[0]) return ids
[документация] def task_children(self, task_id): """ :param int task_id: идентификатор задачи. :returns: таблица подзадач. Поля таблицы описаны в модуле dbtypes: :py:const:`TASK_DATA_...<py_cerebro.dbtypes.TASK_DATA_>` """ tasks = self.execute('select uid from "_task_list_00"($1,0)', task_id) ids = set() for task in tasks: ids.add(task[0]) return self.execute('select * from "taskQuery_11"($1)', ids)
[документация] def task_allocated(self, task_id): """ :param int task_id: идентификатор задачи. :returns: таблица назначенных пользователей (исполнителей) на задачу. Поля таблицы описаны в модуле dbtypes: :py:const:`TASK_ALLOCATED_...<py_cerebro.dbtypes.TASK_ALLOCATED_>` """ return self.execute('select uid, "userNameDisplay"(uid) as name, "userGetFlags"(uid) as flags from "assignedUsersTask"($1) as uid order by name', task_id)
[документация] def task_attachments(self, task_id): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :returns: таблица файловых вложений задачи(задач). Поля таблицы описаны описаны в модуле dbtypes: :py:const:`ATTACHMENT_DATA_...<py_cerebro.dbtypes.ATTACHMENT_DATA_>` Одно вложение может представлять собой от 1-й до 5-ти записей в таблице. Объеденены записи вложения идентификатором группы - :py:const:`ATTACHMENT_DATA_GROUP_ID<py_cerebro.dbtypes.ATTACHMENT_DATA_GROUP_ID>`. Записи одного вложения отличаются тегом :py:const:`ATTACHMENT_DATA_TAG<py_cerebro.dbtypes.ATTACHMENT_DATA_TAG>`, и означают то или иное свойство вложения. Вложение бывает двух видов: файл и ссылка на файл. В первом случаи у вложения присутствует запись с тегом :py:const:`ATTACHMENT_TAG_FILE<py_cerebro.dbtypes.ATTACHMENT_TAG_FILE>`, которая содержит хеш файла, лежащего в файловом хранилище Cargador. В случае если файл приложен к соообщению как ссылка, то присутствует запись с тегом :py:const:`ATTACHMENT_TAG_LINK<py_cerebro.dbtypes.ATTACHMENT_TAG_LINK>`. Эта запись не имеет хеша и в поле имени :py:const:`ATTACHMENT_DATA_FILE_NAME<py_cerebro.dbtypes.ATTACHMENT_DATA_FILE_NAME>` у неё прописан полный путь до файла. Запись с тегом :py:const:`ATTACHMENT_TAG_REVIEW<py_cerebro.dbtypes.ATTACHMENT_TAG_REVIEW>` присутствует только если к файлу добавлена рецензия из инструмента рецензирования Mirada. Записи с тегом эскизов :py:const:`ATTACHMENT_TAG_THUMB...<py_cerebro.dbtypes.ATTACHMENT_TAG_THUMB1>`, присутствуют только, если файл является изображением или видео. В случае изображения присутствует только одна запись :py:const:`ATTACHMENT_TAG_THUMB1<py_cerebro.dbtypes.ATTACHMENT_TAG_THUMB1>`, если видеофайл -- три записи. """
[документация] def task_definition(self, task_id): """ :param int task_id: идентификатор задачи. :returns: данные сообщения типа *Постановка задачи*. Поля таблицы описаны в модуле dbtypes: :py:const:`MESSAGE_DATA_...<py_cerebro.dbtypes.MESSAGE_DATA_>` """ id = self.execute('select "getTaskDefinitionId"($1)', task_id) if (len(id) == 1 and id[0][0] != None): definition = self.execute('select * from "eventQuery_08"($1)', {id[0][0],}) if len(definition) == 1: return definition[0] return None
[документация] def task_messages(self, task_id): """ :param int task_id: идентификатор задачи. :returns: таблица сообщений задачи. Поля таблицы описаны в модуле dbtypes: :py:const:`MESSAGE_DATA_...<py_cerebro.dbtypes.MESSAGE_DATA_>` Типы сообщений описаны в модуле dbtypes: :py:const:`MESSAGE_TYPE_...<py_cerebro.dbtypes.MESSAGE_TYPE_>` """ messs = self.execute('select uid from "_event_list"($1, false)', task_id) ids = set() for mess in messs: ids.add(mess[0]) return self.execute('select * from "eventQuery_08"($1)', ids)
[документация] def task_possible_statuses(self, task_id): """ :param int task_id: идентификатор задачи. :returns: таблица статусов, которые можно установить задаче. Поля таблицы описаны в модуле dbtypes: :py:const:`STATUS_DATA_...<py_cerebro.dbtypes.STATUS_DATA_>` В системе Cerebro для каждого статуса настраиваются разрешения на переключение для каждого статуса. Кроме того, у каждого статуса есть флаг наследственности. На задачи-контейнеры можно устанавливать только те статусы, у которых включен этот флаг. Поэтому список возможных статусов зависит от прав пользователя, текущего статуса, а так же наличия/отсутсвия подзадач у задачи. """ return self.execute('select * from "statusListByTask"($1)', task_id)
[документация] def message(self, message_id): """ :param int message_id: идентификатор сообщения. :returns: данные сообщения. Поля таблицы описаны в модуле dbtypes: :py:const:`MESSAGE_DATA_...<py_cerebro.dbtypes.MESSAGE_DATA_>` Типы сообщений описаны в модуле dbtypes: :py:const:`MESSAGE_TYPE_...<py_cerebro.dbtypes.MESSAGE_TYPE_>` """ mess = self.execute('select * from "eventQuery_08"($1)', {message_id,}) if len(mess) == 1: return mess[0] return None
[документация] def messages(self, message_ids): """ :param message_id: идентификатор сообщения(сообщений). :type message_id: int, set(int, ) или list(int, ) :returns: данные сообщения(сообщений). Поля таблицы описаны в модуле dbtypes: :py:const:`MESSAGE_DATA_...<py_cerebro.dbtypes.MESSAGE_DATA_>` Типы сообщений описаны в модуле dbtypes: :py:const:`MESSAGE_TYPE_...<py_cerebro.dbtypes.MESSAGE_TYPE_>` """
[документация] def message_attachments(self, message_id): """ :param message_id: идентификатор сообщения или массив идентификаторов сообщений. :type message_id: int, set(int, ) или list(int, ) :returns: таблица файловых вложений сообщения(ий). Поля таблицы описаны описаны в модуле dbtypes: :py:const:`ATTACHMENT_DATA_...<py_cerebro.dbtypes.ATTACHMENT_DATA_>` Одно вложение может представлять собой от 1-й до 5-ти записей в таблице. Объеденены записи вложения идентификатором группы - :py:const:`ATTACHMENT_DATA_GROUP_ID<py_cerebro.dbtypes.ATTACHMENT_DATA_GROUP_ID>`. Записи одного вложения отличаются тегом :py:const:`ATTACHMENT_DATA_TAG<py_cerebro.dbtypes.ATTACHMENT_DATA_TAG>`, и означают то или иное свойство вложения. Вложение бывает двух видов: файл и ссылка на файл. В первом случаи у вложения присутствует запись с тегом :py:const:`ATTACHMENT_TAG_FILE<py_cerebro.dbtypes.ATTACHMENT_TAG_FILE>`, которая содержит хеш файла, лежащего в файловом хранилище Cargador. В случае если файл приложен к соообщению как ссылка, то присутствует запись с тегом :py:const:`ATTACHMENT_TAG_LINK<py_cerebro.dbtypes.ATTACHMENT_TAG_LINK>`. Эта запись не имеет хеша и в поле имени :py:const:`ATTACHMENT_DATA_FILE_NAME<py_cerebro.dbtypes.ATTACHMENT_DATA_FILE_NAME>` у неё прописан полный путь до файла. Запись с тегом :py:const:`ATTACHMENT_TAG_REVIEW<py_cerebro.dbtypes.ATTACHMENT_TAG_REVIEW>` присутствует только если к файлу добавлена рецензия из инструмента рецензирования Mirada. Записи с тегом эскизов :py:const:`ATTACHMENT_TAG_THUMB...<py_cerebro.dbtypes.ATTACHMENT_TAG_THUMB1>`, присутствуют только, если файл является изображением или видео. В случае изображения присутствует только одна запись :py:const:`ATTACHMENT_TAG_THUMB1<py_cerebro.dbtypes.ATTACHMENT_TAG_THUMB1>`, если видеофайл -- три записи. """ return self.execute('select * from "listAttachmentsArray"($1, false)', {message_id,})
[документация] def users(self): """ :returns: таблица пользователей/материальных ресурсов. Поля таблицы описаны в модуле dbtypes: :py:const:`USER_DATA_...<py_cerebro.dbtypes.USER_DATA_>` У материального ресурса выставлен флаг :py:const:`USER_FLAG_IS_RESOURCE<py_cerebro.dbtypes.USER_FLAG_IS_RESOURCE>`. Проверить этот флаг можно с помощью функции :py:func:`cclib.has_flag<py_cerebro.cclib.has_flag>`:: if cclib.has_flag(user[dbtypes.USER_DATA_FLAGS], dbtypes.USER_FLAG_IS_RESOURCE): #если материальный ресурс # действия """ return self.execute('select uid, "userNameDisplay"(uid) as name, "userGetFlags"(uid) as flags' + ', "userGetLogin"(uid) as lid, "userGetFirstName"(uid) as firstname, "userGetLastName"(uid) as lastname' + ', "userGetEmail"(uid) as email, "userGetPhone"(uid) as phone, "userGetIcq"(uid) as icq from "userList"() order by name')
[документация] def activities(self): """ :returns: таблица видов деятельности. Поля таблицы описаны в модуле dbtypes: :py:const:`ACTIVITY_DATA_...<py_cerebro.dbtypes.ACTIVITY_DATA_>` """ return self.execute('select uid, name from "listActivities"(false)')
[документация] def statuses(self): """ :returns: таблица всех статусов. Поля таблицы описаны в модуле dbtypes: :py:const:`STATUS_DATA_...<py_cerebro.dbtypes.STATUS_DATA_>` """ return self.execute('select * from "statusList"()')
[документация] def add_task(self, parent_id, name, activity_id = 0): """ :param int parent_id: идентификатор родительской задачи. :param string name: имя новой задачи. :param int activity_id: идентификатор вида деятельности. По умолчанию равен '0' (Нет вида деятельности). :returns: идентификатор новой задачи. Создание новой задачи. Имя задачи не может содержать символы: **\\\\ / # : ? & ' " , + |**. .. note:: Для отправки уведомления пользователю о новой задаче требуется создать в задаче сообщение типа :py:meth:`"Постановка задачи" <py_cerebro.database.Database.add_definition>`. """ match = re.search(r"[\\\\/#:?&'\",|+]+", name) if match: raise Exception("Name is incorrect. Symbols \\ / # : ? & ' \" , + | are not allowed") return self.execute('select "newTask_00"($1,$2,$3,true)', parent_id, name, activity_id)[0][0]
[документация] def task_set_name(self, task_id, name): """ :param int task_id: идентификатор задачи. :param string name: новое имя задачи. Устанавливает новое имя задачи. Новое имя не может содержать символы: **\\\\ / # : ? & ' " , + |**. """ match = re.search(r"[\\\\/#:?&'\",|+]+", name) if match: raise Exception("Name is incorrect. Symbols \\ / # : ? & ' \" , + | are not allowed") return self.execute('select "taskSetName"($1,$2)', task_id, name)[0][0]
[документация] def task_set_activity(self, task_id, activity_id): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param int activity_id: идентификатор вида деятельности. Устанавливает вид деятельности задачи(задач). Идентификатор вида деятельности = 0 переводит вид деятельности задачи в 'Нет вида деятельности'. """ return self.execute('select "taskSetActivity_a"($1,$2)', {task_id, }, activity_id)[0][0]
[документация] def task_set_status(self, task_id, status_id): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param int status_id: идентификатор статуса. Устанавливает статус задачи. Идентификатор статуса = None переводит статус задачи в 'Нет статуса'. """ return self.execute('select "taskSetStatus_a"($1,$2)', {task_id, }, status_id)[0][0]
[документация] def task_set_priority(self, task_id, prior): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param int prior: значение приоритета. Устанавливает приоритет задачи. Значения приоритета описаны в модуле dbtypes: :py:const:`TASK_PRIORITY_...<py_cerebro.dbtypes.TASK_PRIORITY_>` """ return self.execute('select "taskSetPriority_a"($1,$2)', {task_id, }, prior)[0][0]
[документация] def task_set_flag(self, task_id, flag, is_set): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param int flag: значение флага. :param bool is_set: признак установки/сброса флага. Устанавливает флаг у задачи. Если аргумент *is_set* равен True, то флаг устанавливается, иначе сбрасывается. :: # Пометить задачу как архивную db.task_set_flag(task_id, dbtypes.TASK_FLAG_ARCHIVED, True) Значения флагов задачи описаны в модуле dbtypes: :py:const:`TASK_FLAG_...<py_cerebro.dbtypes.TASK_FLAG_>` """ newFlag = 0 if is_set: newFlag = 1 << flag mask = 1 << flag self.execute('select "taskSetFlagsMulti"($1,$2,$3)', {task_id, }, newFlag, mask)
[документация] def task_set_progress(self, task_id, progress): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param int progress: значение прогресса. Устанавливает прогресс задачи. При установке прогреса в 100 задача считается Выполненой (Done). При установке прогреса в None собственный прогресс задачи сбрасывается и рассчитывается из подзадач. """ return self.execute('select "taskSetProgress_a"($1,$2)', {task_id, }, progress)[0][0]
[документация] def task_set_planned_time(self, task_id, hours): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param float hours: запланированные на задачу часы. Устанавливает запланированное время задачи(задач) в часах. При установке аргумента hours в None, запланированное время задачи сбрасывается. После сброса запланированное время рассчитывается исходя из календарных сроков задачи и расписания. """ return self.execute('select "taskSetPlanned_a"($1,$2)', {task_id, }, hours)[0][0]
[документация] def task_set_start(self, task_id, time): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param float time: время в днях от 01.01.2000. Устанавливает время начала задачи в днях от 01.01.2000 в UTC Аргумент time = None сбрасывает установленное время начала задачи. После сброса время начала рассчитывается исходя из связей задачи и расписания. :: db.task_set_start({task_id, task_id1}, 4506.375) # время старта 03.05.2012 9:00 UTC Пример установки времени начала задачи в текущее :: import datetime datetime_now = datetime.datetime.utcnow() datetime_2000 = datetime.datetime(2000, 1, 1) timedelta = datetime_now - datetime_2000 days = timedelta.total_seconds()/(24*60*60) db.task_set_start(task_id, days) """ return self.execute('select "ggSetTaskOffset_a"($1,$2::double precision)', {task_id, }, time)[0][0]
[документация] def task_set_finish(self, task_id, time): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param float time: время в днях от 01.01.2000 (UTC), Устанавливает время окончания задачи(Задач) в днях от 01.01.2000 в UTC. Аргумент time = None сбрасывает установленное время окончания задачи, в этом случае время окончания рассчитывается исходя из запланированного времени на задачу и расписания. :: db.task_set_finish(task_id, 4506.75) # время окончания 03.05.2012 18:00 UTC Пример установки времени окончания задачи через 3 дня от текущего :: import datetime datetime_now = datetime.datetime.utcnow() datetime_2000 = datetime.datetime(2000, 1, 1) timedelta = datetime_now - datetime_2000 days = timedelta.total_seconds()/(24*60*60) + 3 db.task_set_finish(task_id, days) """ return self.execute('select "ggSetTaskStop_a"($1,$2::double precision)', {task_id, }, time)[0][0]
[документация] def task_set_budget(self, task_id, budget): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param float budget: величина бюджета в условных единицах. Устанавливает бюджет задачи. При установке бюджета в None, собственный бюджет задачи сбрасывается и рассчитывается из подзадач. """ return self.execute('select "taskSetCosts_a"($1,$2)', {task_id, }, budget)[0][0]
[документация] def task_set_allocated(self, task_id, user_id): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param user_id: идентификатор пользователя/материального ресурса или массив идентификаторов пользователей/материальных ресурсов. :type user_id: int, set(int, ) или list(int, ) Назначает исполнителя на задачу. .. note:: Для отправки уведомления исполнителю о назначенной задаче необходимо наличие в задаче сообщения типа :py:meth:`"Постановка задачи" <py_cerebro.database.Database.task_definition>`. """ return self.execute('select "userAssignmentTask_a"($1,$2,$3)', {task_id, }, {user_id, }, 1)[0][0]
[документация] def task_remove_allocated(self, task_id, user_id): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param user_id: идентификатор пользователя/материального ресурса или массив идентификаторов пользователей/материальных ресурсов. :type user_id: int, set(int, ) или list(int, ) Убирает исполнителя с задачи. """ return self.execute('select "userAssignmentTask_a"($1,$2,$3)', {task_id, }, {user_id, }, 0)[0][0]
[документация] def task_set_hashtags(self, task_id, hashtags): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param hashtags: список хэштегов(каждый хэштег должен быть одним словом без пробелов). :type hashtags: string, set(string, ) или list(string, ) Устанавливает хэштеги на задачи. """ tasks = self.execute('select "htSetTask"(%s,%s,%s)', get_val_by_type(task_id), hashtags, True) ids = set() for task in tasks: ids.add(task[0]) return ids
[документация] def task_hashtags(self, task_id): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) Получает хэштеги задачи. :: # Работа с хэштегами задачи to_do_task_list = db.to_do_task_list(db.current_user_id(), True) db.task_set_hashtags(to_do_task_list[0][dbtypes.TASK_DATA_ID], {'хэштег1', 'хэштег2', 'хэштег3'}) # присваиваем задаче массив хэштегов db.task_remove_hashtags(to_do_task_list[0][dbtypes.TASK_DATA_ID], 'хэштег2') # удаляем хэштег hashtags = db.task_hashtags(to_do_task_list[0][dbtypes.TASK_DATA_ID]) # получаем хэштеги задачи print('Хэштеги задачи ', hashtags) # распечатываем хэштеги """ hashtags = '' #self.execute('select "htSetTask"(%s,%s,%s)', get_val_by_type(task_id), hashtags, True) return hashtags
[документация] def task_remove_hashtags(self, task_id, hashtags): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param hashtags: список хэштегов(каждый хэштег должен быть одним словом без пробелов). :type hashtags: string, set(string, ) или list(string, ) Удаляет хэштеги из задач. """ tasks = self.execute('select "htSetTask"(%s,%s,%s)', get_val_by_type(task_id), hashtags, False) ids = set() for task in tasks: ids.add(task[0]) return ids
[документация] def message_set_hashtags(self, message_id, hashtags): """ :param message_id: идентификатор сообщения или массив идентификаторов сообщений. :type message_id: int, set(int, ) или list(int, ) :param hashtags: список хэштегов(каждый хэштег должен быть одним словом без пробелов). :type hashtags: string, set(string, ) или list(string, ) Устанавливает хэштеги на сообщения. """ tasks = self.execute('select "htSetEvent"(%s,%s,%s)', get_val_by_type(message_id), hashtags, True) ids = set() for task in tasks: ids.add(task[0]) return ids
[документация] def message_hashtags(self, message_id): """ :param message_id: идентификатор сообщения или массив идентификаторов сообщений. :type message_id: int, set(int, ) или list(int, ) Получает хэштеги сообщения. """ hashtags = ''#self.execute('select "htSetEvent"(%s,%s,%s)', get_val_by_type(message_id), hashtags, True) return hashtags
[документация] def message_remove_hashtags(self, message_id, hashtags): """ :param message_id: идентификатор сообщения или массив идентификаторов сообщений. :type message_id: int, set(int, ) или list(int, ) :param hashtags: список хэштегов(каждый хэштег должен быть одним словом без пробелов). :type hashtags: string, set(string, ) или list(string, ) Удаляет хэштеги из сообщений. """ tasks = self.execute('select "htSetEvent"(%s,%s,%s)', get_val_by_type(message_id), hashtags, False) ids = set() for task in tasks: ids.add(task[0]) return ids
[документация] def attachment_set_hashtags(self, attachment_id, hashtags): """ :param attachment_id: идентификатор вложения или массив идентификаторов вложений. :type attachment_id: int, set(int, ) или list(int, ) :param hashtags: список хэштегов(каждый хэштег должен быть одним словом без пробелов). :type hashtags: string, set(string, ) или list(string, ) Устанавливает хэштеги на вложения. .. note:: Рекомендуется для вложений со значением тега ATTACHMENT_DATA_TAG: ATTACHMENT_TAG_FILE или ATTACHMENT_TAG_LINK. """ tasks = self.execute('select "htSetAttachment"(%s,%s,%s)', get_val_by_type(attachment_id), hashtags, True) ids = set() for task in tasks: ids.add(task[0]) return ids
[документация] def attachment_hashtags(self, attachment_id): """ :param attachment_id: идентификатор вложения или массив идентификаторов вложений. :type attachment_id: int, set(int, ) или list(int,) Получает хэштеги вложения. .. note:: Рекомендуется для вложений со значением тега ATTACHMENT_DATA_TAG: ATTACHMENT_TAG_FILE или ATTACHMENT_TAG_LINK. """ hashtags = ''#self.execute('select "htSetAttachment"(%s,%s,%s)', get_val_by_type(attachment_id), hashtags, True) return hashtags
[документация] def attachment_remove_hashtags(self, attachment_id, hashtags): """ :param attachment_id: идентификатор вложения или массив идентификаторов вложений. :type attachment_id: int, set(int, ) или list(int, ) :param hashtags: список хэштегов(каждый хэштег должен быть одним словом без пробелов). :type hashtags: string, set(string, ) или list(string, ) Удаляет хэштеги их вложений. .. note:: Рекомендуется для вложений со значением тега ATTACHMENT_DATA_TAG: ATTACHMENT_TAG_FILE или ATTACHMENT_TAG_LINK. """ tasks = self.execute('select "htSetAttachment"(%s,%s,%s)', get_val_by_type(attachment_id), hashtags, False) ids = set() for task in tasks: ids.add(task[0]) return ids
[документация] def add_definition(self, task_id, html_text): """ :param int task_id: идентификатор задачи. :param string html_text: текст сообщения в формате html. :returns: идентификатор нового сообщения. :rtype: int Добавляет сообщение типа "Постановка задачи". """ return self.execute('select "eventNew"($1,$2,$3,$4,$5,$6)', None, task_id, html_text, MESSAGE_TYPE_DEFINITION, None, None)[0][0]
[документация] def add_review(self, task_id, message_id, html_text, minutes = None): """ :param int task_id: идентификатор задачи. :param int message_id: идентификатор сообщения, на которое пишется ответ. :param string html_text: текст сообщения в формате html. :param int minutes: принятое время в минутах. :returns: идентификатор нового сообщения. :rtype: int Добавляет сообщение типа "Рецензия". """ return self.execute('select "eventNew"($1,$2,$3,$4,$5,$6)', None, task_id, html_text, MESSAGE_TYPE_REVIEW, message_id, minutes)[0][0]
[документация] def add_client_review(self, task_id, message_id, html_text): """ :param int task_id: идентификатор задачи. :param int message_id: идентификатор сообщения, на которое пишется ответ. :param string html_text: текст сообщения в формате html. :returns: идентификатор нового сообщения. :rtype: int Добавляет сообщение типа "Рецензия клиента". """ return self.execute('select "eventNew"($1,$2,$3,$4,$5,$6)', None, task_id, html_text, MESSAGE_TYPE_CLIENT_REVIEW, message_id, None)[0][0]
[документация] def add_report(self, task_id, message_id, html_text, minutes): """ :param int task_id: идентификатор задачи. :param int message_id: идентификатор сообщения, на которое пишется ответ. :param string html_text: текст сообщения в формате html. :param int minutes: заявленое время отчета в минутах. :returns: идентификатор нового сообщения. :rtype: int Очень важнп устанавливать время в отчетах. Если minutes имеет занчение 0 или None, отчет не попадет в статистику. Добавляет сообщение типа "Отчет". """ return self.execute('select "eventNew"($1,$2,$3,$4,$5,$6)', None, task_id, html_text, MESSAGE_TYPE_REPORT, message_id, minutes)[0][0]
[документация] def add_resource_report(self, task_id, message_id, resource_id, html_text, minutes): """ :param int task_id: идентификатор задачи. :param int message_id: идентификатор сообщения, на которое пишется ответ. :param int resource_id: идентификатор материального ресурса, за который пишется отчет. :param string html_text: текст сообщения в формате html. :param int minutes: заявленое время отчета в минутах. :returns: идентификатор нового сообщения. :rtype: int Добавляет сообщение типа "Отчет за ресурс". """ return self.execute('select "eventNew"($1,$2,$3,$4,$5,$6)', resource_id, task_id, html_text, MESSAGE_TYPE_RESOURCE_REPORT, message_id, minutes)[0][0]
[документация] def add_note(self, task_id, message_id, html_text): """ :param int task_id: идентификатор задачи. :param int message_id: идентификатор сообщения, на которое пишется ответ. :param string html_text: текст сообщения в формате html. :returns: идентификатор нового сообщения. :rtype: int Добавляет сообщение типа "Заметка". """ return self.execute('select "eventNew"($1,$2,$3,$4,$5,$6)', None, task_id, html_text, MESSAGE_TYPE_NOTE, message_id, None)[0][0]
[документация] def add_attachment(self, message_id, carga, filename, thumbnails, description, as_link): """ :param int message_id: идентификатор сообщения. :param py_cerebro.cargador.Cargador carga: объект класса :py:class:`cargador.Cargador<py_cerebro.cargador.Cargador>`, для импортирования файлов в файловое хранилище. :param string filename: полный путь до файла. :param thumbnails: список путей до файлов эскизов (не больше трех). Размер эскизов должен быть 512x512. Формат JPG или PNG. :param string description: пояснения(комментарии) к вложению. :param bool as_link: способ добавления файла к сообщению: True - файл добавляется как ссылка; False - файл добавляется как вложение, то есть импортируется в файловое хранилище(Cargador). Добавление вложения к сообщению. **Использование для генерации эскизов.** Если файл является изображением или видео, то можно добавить для него уменьшенные эскизы. Можно добавить до 3-х эскизов (первый, средний, последний кадры). Для генерации эскизов можно использовать программу Mirada. Она поставляется вместе с дистрибутивом Cerebro. :: #Пример генерации эскизов с помощью Mirada. gen_path = os.path.dirname(filename) # В качестве директории для генерации эскизов возьмем директорию добавляемого файла mirada_path = './mirada' # путь до исполняемого файла программы Mirada # Запускаем мираду с необходимыми ключами 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. #Для того, чтобы генерить эскизы с помощью 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 """ if os.path.exists(filename) == False: raise Exception('File ' + filename + ' not found') """ Приложение файла к сообщению состоит из двух этапов 1 - добавление файла в файловое хранилище (Cargador) Этот этап пропускается, если файл прикладывается как ссылка 2 - добавление записи(ей) в базу данных об этом файле """ hash = '' if as_link != True and carga: # Если файл добавляется не как ссылка, добавляем его в Cargador и получаем его хеш # Запрос на получение текстового локатора задачи rtask_url = self.execute('select "getUrlBody_byTaskId_00"((select taskid from "eventQuery_08"($1)))', {message_id, }) task_url = rtask_url[0][0] hash64 = carga.import_file(filename, task_url) # Импортирование файла в хранилище hash = hash64_16(hash64) if hash == None or len(hash) == 0: # Если хеш не получен генерируем исключение raise Exception('Хеш не задан') tag = ATTACHMENT_TAG_FILE file_size = 0 file_name = '' if as_link == True: tag = ATTACHMENT_TAG_LINK file_name = filename else: file_size = os.stat(filename).st_size file_name = os.path.basename(filename) """ Параметр tag нужен для определения вложения: dbtypes.ATTACHMENT_TAG_FILE - файл является вложением, то есть он находится в файловом хранилище Cargador и у него есть хеш dbtypes.ATTACHMENT_TAG_LINK - файл приложен как ссылка на файл(папку). Параметр file_size - размер файла в байтах. Для ссылки задаётся в 0. Параметр file_name - имя файла. Для ссылки должен быть полный путь до файла. Для вложения только базовое имя Параметр description - пояснения(комментарии) к приложенному файлу """ # Получаем новый идентификатор для записи о файле в базу данных rnew_attach_id = self.execute('select "getNewAttachmentGroupID"()') # Выполняем запрос на новый идентификатор new_attach_id = rnew_attach_id[0][0] # Добавление записи о файле self.execute('select "newAtachment_00_"($1::bigint, $2::integer, $3, $4::integer, $5::bigint, $6, $7)', message_id, new_attach_id, hash, tag, file_size, file_name, description) # Выполняем запрос для записи о файле """ Добавляемый файл может иметь несколько записей, например он может иметь уменшенные эскизы или рицензию. Для добавления дополнительных записей о файле должен использоватся тот же идентификатор, но различные теги. Если вы решите переделать скрипт для добавления нескольких файлов, то для каждого файла вам нужно получать новый идентификатор. """ if thumbnails != None and len(thumbnails) > 0 and carga: # Добавляем эскизы в файловое хранилище и получаем их хеши hashthumbs = list() for f in thumbnails: th_hash64 = carga.import_file(f, 'thumbnail.cache') # Импортирование эскиза файла в хранилище th_hash = hash64_16(th_hash64) hashthumbs.append(th_hash) # Добавляем хеши эскизов в базу данных for i in range(len(hashthumbs)): if i > 2: break tag = i+1 # Задаем тег для эскиза. 1 - первый эскиз, 2 - средний, 3 - последний # Добавление записи о эскизе self.execute('select "newAtachment_00_"($1::bigint, $2::integer, $3, $4::integer, $5::bigint, $6, $7)', message_id, new_attach_id, hashthumbs[i], tag, 0, '', '') # Выполняем запрос для записи о эскизе """ Такие параметры как размер, имя файла и пояснения для эскизов не нужны, поэтому они забиваются пустыми полями """ return new_attach_id
[документация] def project_tags(self, project_id): """ :param int project_id: идентификатор проекта. :returns: таблица тегов проекта. Таблица содержит все теги, которые можно задавать на задачах проекта. Поля таблицы описаны в модуле dbtypes: :py:const:`TAG_DATA_...<py_cerebro.dbtypes.TAG_DATA_>` """ return self.execute('select * from "tagSchemaList_byPrj"($1)', project_id)
[документация] def tag_enums(self, tag_id): """ :param int tag_id: идентификатор тега. :returns: таблица перечеслений тега. Таблица содержит перечесления, которые можно установить в качестве значения тега. Поля таблицы описаны в модуле dbtypes: :py:const:`TAG_ENUM_DATA_...<py_cerebro.dbtypes.TAG_ENUM_DATA_>` """ return self.execute('select * from "tagEnumList"($1, false)', tag_id)
[документация] def task_set_tag_enum(self, task_id, enum_id, is_set): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param enum_id: идентификатор перечесления или массив идентификаторов перечислений. :type enum_id: int, set(int, ) или list(int, ) :param bool is_set: признак установки/сброса перечесления. Устанавливает или убирает для задачи(задач) значение тега с типом перечесление или множественное перечесление. В случаи с тегом типа множественное перечесление, функция добавляет перечесления/удаляет перечесления к значению тега. В случаи с типом перечесление, происходит замена предыдущего установленого перечесления. """ return self.execute('select "tagTaskSetEnum_a"($1,$2,$3)', {enum_id, }, {task_id, }, is_set)[0][0]
[документация] def task_set_tag_float(self, task_id, tag_id, value): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param int tag_id: идентификатор тега. :param float value: значение тега. Устанавливает для задачи(задач) значение тега с типом число с плавающей точкой. """ return self.execute('select "tagTaskSetReal_a"($1,$2,$3)', tag_id, {task_id, }, value)[0][0]
[документация] def task_set_tag_int(self, task_id, tag_id, value): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param int tag_id: идентификатор тега. :param int value: значение тега. Устанавливает для задачи(задач) значение тега с целочисленным типом. """ return self.execute('select "tagTaskSetInt_a"($1,$2,$3)', tag_id, {task_id, }, value)[0][0]
[документация] def task_set_tag_string(self, task_id, tag_id, value): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param int tag_id: идентификатор тега. :param string value: значение тега. Устанавливает для задачи(задач) значение тега с типом строка. """ return self.execute('select "tagTaskSetStr_a"($1,$2,$3)', tag_id, {task_id, }, value)[0][0]
[документация] def task_tag_reset(self, task_id, tag_id): """ :param task_id: идентификатор задачи или массив идентификаторов задач. :type task_id: int, set(int, ) или list(int, ) :param int tag_id: идентификатор тега. Сбрасывает значение тега для задачи(задач). """ return self.execute('select "tagTaskReset_a"($1,$2)', tag_id, {task_id, })[0][0]
[документация] def task_tag_enums(self, task_id, tag_id): """ :param int task_id: идентификатор задачи. :param int tag_id: идентификатор тега. :returns: таблица установленных на задачу перечеслений тега. Поля таблицы описаны в модуле dbtypes: :py:const:`TASK_TAG_ENUM_...<py_cerebro.dbtypes.TASK_TAG_ENUM_>` """ return self.execute('select * from "tagTaskEnums"($1,$2)', task_id, tag_id)
[документация] def task_tags(self, task_id): """ :param int task_id: идентификатор задачи. :returns: таблица установленных на задачу значений тегов. Поля таблицы описаны в модуле dbtypes: :py:const:`TASK_TAG_DATA_...<py_cerebro.dbtypes.TASK_TAG_DATA_>` """ return self.execute('select * from "tagTaskList"($1)', task_id)
[документация] def task_by_url(self, url): """ :param string url: путь до задачи. :returns: ID задачи. Возвращает ID задачи по пути к задаче. Пример пути к задаче: '/Test project/test'. .. note:: Пути к задаче регистрозависимы. """ pass