예제 #1
0
class Megaplan(object):
    """
    """
    debug = False

    HOST = '{account}.megaplan.ru/'
    SIGNATURE = '{method}\n{md5content}\n{contenttype}\n{date}\n{host}{uri}'

    _CommonApi = 'BumsCommonApiV01/'
    _ProjectApi = 'BumsProjectApiV01/'
    _StaffApi = 'BumsStaffApiV01/'
    _TaskApi = 'BumsTaskApiV01/'
    _TimeApi = 'BumsTimeApiV01/'
    _TradeApi = 'BumsTradeApiV01/'

    AUTHORIZE = _CommonApi + 'User/'
    COMMENT = _CommonApi + 'Comment/'
    DEAL = _TradeApi + 'Deal/'
    DEPARTMENT = _StaffApi + 'Department/'
    EMPLOYEE = _StaffApi + 'Employee/'
    EVENT = _TimeApi + 'Event/'
    FAVORITE = _CommonApi + 'Favorite/'
    INFORMER = _CommonApi + 'Informer/'
    PROJECT = _ProjectApi + 'Project/'
    SEARCH = _CommonApi + 'Search/'
    SEVERITY = _TaskApi + 'Severity/'
    TASK = _TaskApi + 'Task/'
    TODOLIST = _TimeApi + 'TodoList/'

    code = 'utf-8'

    _FolderType = (
        'incoming',
        'responsible',
        'executor',
        'owner',
        'auditor',
        'all',
    )
    _StatusType = (
        'actual',
        'inprocess',
        'new',
        'overdue',
        'done',
        'delayed',
        'completed',
        'failed',
        'any',
    )
    _ActionType = (
        'act_accept_task',
        'act_reject_task',
        'act_accept_work',
        'act_reject_work',
        'act_done',
        'act_pause',
        'act_resume',
        'act_cancel',
        'act_expire',
        'act_renew',
    )
    _SubjectType = (
        'task',
        'project',
    )
    _OrderType = (
        'asc',
        'desc',
    )

    @property
    def Account(self):
        return self._Account

    @Account.setter
    def Account(self, account):
        self._Account = account
        self._host = self.HOST.format(account=account)
        self._MPQuery = 'https://{host}{uri}'.format(host=self._host,
                                                     uri='{uri}')

    @property
    def Login(self):
        return self._Login

    @Login.setter
    def Login(self, login):
        self._Login = login

    @property
    def Password(self):
        return self._Password

    @Password.setter
    def Password(self, password):
        self._Password = password

    def __init__(self, account='', login='', password=''):
        self.Account, self.Login, self.Password = account, login, password

        self._client = APIClient()
        self._data = str()

        self._AccessId = str()
        self._SecretKey = str()

    def _TimeAsRfc822(self, dt):
        return formatdate(
            mktime_tz(parsedate_tz(dt.strftime('%a, %d %b %Y %H:%M:%S'))))

    def _GetResponseObject(f):
        def wrapper(self):
            obj = JSON2Obj(self._data)
            if 'error' == obj.status['code']:
                if 'message' in obj.status:
                    raise Exception(obj.status['message'])
            return f(self, obj)

        return wrapper

    @_GetResponseObject
    def _AuthorizeHandle(self, obj):
        self._AccessId = obj.data['AccessId']
        self._SecretKey = obj.data['SecretKey']

        if self.debug:
            self._MPQuery = 'http://{host}'.format(host=self._host) + '{uri}'

    def _Authorize(self):
        uri = self.AUTHORIZE + 'authorize.api'
        md5pass = md5.new(self.Password).hexdigest()
        params = {'Login': self.Login, 'Password': md5pass}
        self._data = \
            self._client.Request(self._MPQuery.format(uri=uri), params)
        self._AuthorizeHandle()

    def _Auth(f):
        def wrapper(self, *args, **kwargs):
            if (self._AccessId == '') or (self._SecretKey == ''):
                self._Authorize()
            return f(self, *args, **kwargs)

        return wrapper

    def _GetSignature(self, method, uri, params={}):
        self._rfcdate = self._TimeAsRfc822(datetime.now())
        self._md5content = ''
        contenttype = ''
        if 'POST' == method:
            self._md5content = md5.new(urlencode(params)).hexdigest()
            contenttype = 'application/x-www-form-urlencoded'
        sign = {
            'method': method,
            'md5content': self._md5content,
            'contenttype': contenttype,
            'date': self._rfcdate,
            'host': self._host,
            'uri': uri
        }
        q = self.SIGNATURE.format(**sign)
        h = hmac.HMAC(self._SecretKey.encode(self.code), q, sha1)
        return base64.encodestring(h.hexdigest()).strip()

    def _GetHeaders(self, uri, params={}):
        method = 'GET'
        if params:
            method = 'POST'
        signature = self._GetSignature(method, uri, params)
        header = {
            'User-Agent':
            'Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7',
            'Accept':
            'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language': 'ru,en-us;q=0.7,en;q=0.3',
            'Accept-Encoding': 'gzip,deflate',
            'Accept-Charset': 'utf-8;q=0.7,*;q=0.7',
            'Keep-Alive': '300',
            'Connection': 'keep-alive',
            'Date': self._rfcdate,
            'X-Authorization': '{0}:{1}'.format(self._AccessId, signature)
        }
        if method == 'GET':
            header['Accept'] = 'application/json'
        elif method == 'POST':
            header['Content-MD5'] = self._md5content
        return header

    @_GetResponseObject
    def _ResponseHandle(self, obj):
        return obj

    @_Auth
    def _GetData(self, uri, params={}):
        headers = self._GetHeaders(uri, params)
        self._data = self._client.Request(self._MPQuery.format(uri=uri),
                                          params=params,
                                          headers=headers)
        if self._client.Status in (400, 401, 403, 404, 500):
            raise ClientError('{0} {1}'.format(self._client.Status,
                                               self._client.Reason))
        return self._ResponseHandle()

    def GetData(self):
        return self._data

    def Tasks(self,
              Folder='all',
              Status='any',
              FavoritesOnly=False,
              Search=''):
        """
        input:
            Folder='all': string = ('incoming' (входящие),
                'responsible' (ответственный), 'executor' (соисполнитель),
                'owner' (исходящие), 'auditor' (аудируемые),
                'all' (все)) # Папка
            Status='any': string = ('actual' (актуальные),
                'inprocess' (в процессе), 'new' (новые),
                'overdue' (просроченные), 'done' (условно завершенные),
                'delayed' (отложенные), 'completed' (завершенные),
                'failed' (проваленные), 'any' (любые)) # Статус
            FavoritesOnly=0: integer = (0, 1) # Только избранное
            Search='': string = 'любая строка' # Строка поиска
        output:
            tasks<array>:
                Id: integer # ID задачи
                Name: string # Название
                Status: string # Статус
                Deadline: datetime # Дедлайн
                Owner: object(Id, Name) # Постановщик (сотрудник)
                Responsible: object(Id, Name) # Ответственный (сотрудник)
                Severity: object(Id, Name) # Важность
                SuperTask: object(Id, Name) # Надзадача
                Project: object(Id, Name) # Проект
                Favorite: integer # В избранном
                TimeCreated: datetime # Время создания
        """
        if (Folder not in self._FolderType) or (Status
                                                not in self._StatusType):
            raise AttributeError('Invalid parameter value')

        uri = '{0}list.api?Folder={1}&Status={2}&FavoritesOnly={3}&Search={4}'
        uri = uri.format(self.TASK, Folder, Status, int(FavoritesOnly), Search)
        return self._GetData(uri)

    def TaskCard(self, Id):
        """
        input:
            Id: integer # ID задачи. Обязательный параметр
        output:
            task:
                Id: integer # ID задачи
                Name: string # Название
                Statement: string # Суть задачи
                Status: string # Статус
                Deadline: datetime # Дедлайн
                DeadlineType: string # Тип дедлайна
                Owner: object (Id, Name) # Постановщик (сотрудник)
                Responsible: object (Id, Name) # Ответственный (сотрудник)
                Executors: array<object> (Id, Name) # Соисполнители (сотрудники)
                Auditors: array<object> (Id, Name) # Аудиторы (сотрудники)
                Severity: object (Id, Name) # Важность
                SuperTask: object (Id, Name) # Надзадача
                Project: object (Id, Name) # Проект
                SubTasks: array<object>(Id, Name, Owner, Responsible, Deadline,
                    Favorite (версия 2011.02+)) # Подзадачи
                Favorite: integer # В избранном
                TimeCreated: datetime # Время создания
                Customer: object(Id, Name, Status, Type) # Заказчик
                    (код, название, статус, тип)
        """
        uri = '{0}card.api?Id={1}'.format(self.TASK, Id)
        return self._GetData(uri)

    def TaskCreate(self, **kwargs):
        """
        input:
            kwargs:
                Model[Name]: string # Название
                Model[Deadline]: datetime # Дедлайн (дата со временем)
                Model[DeadlineDate]: date # Дедлайн (только дата)
                Model[DeadlineType]: string # Тип дедлайна
                Model[Responsible]: integer # Код ответственного
                Model[Executors]: array<integer> # Коды соисполнителей
                Model[Auditors]: array<integer> # Коды аудиторов
                Model[Severity]: integer # Код важности
                Model[SuperTask]: string # Код надзадачи (если число) или
                    код проекта (если строка в формате ‘p<код проекта>’
                Model[Customer]: integer # Код заказчика
                Model[IsGroup]: integer = (0, 1) # Массовая задача
                    (каждому соисполнителю будет создана своя задача)
                Model[Statement]: string # Суть задачи
        output:
            Id: integer # ID задачи
            Name: string # Название задачи
        """
        uri = '{0}create.api'.format(self.TASK)
        return self._GetData(uri, kwargs)

    def TaskEdit(self, Id, **kwargs):
        """
        input:
            Id: integer # ID задачи. Обязательный параметр
            kwargs:
                Model[Name]: string # Название
                Model[Deadline]: datetime # Дедлайн (дата со временем)
                Model[DeadlineDate]: date # Дедлайн (только дата)
                Model[DeadlineType]: string # Тип дедлайна
                Model[Owner]: integer # Код постановщика
                Model[Responsible]: integer # Код ответственного
                Model[Executors]: array<integer> # Коды соисполнителей
                Model[Auditors]: array<integer> # Коды аудиторов
                Model[Severity]: integer # Код важности
                Model[SuperTask]: string # Код надзадачи (если число) или
                    код проекта (если строка в формате ‘p<код проекта>’
                Model[Customer]: integer # Код заказчика
                Model[Statement]: string # Суть задачи
        output:
            None
        """
        uri = '{0}edit.api'.format(self.TASK)
        kwargs['Id'] = str(Id)
        self._GetData(uri, kwargs)

    def TaskAction(self, Id, Action):
        """
        input:
            Id: integer # ID задачи. Обязательный параметр
            Action: string = ('act_accept_task' (принять задачу),
                'act_reject_task' (отклонить задачу),
                'act_accept_work' (принять работу),
                'act_reject_work' (отклонить работу),
                'act_done' (завершить задачу), 'act_pause' (поставить на паузу),
                'act_resume' (возобновить задачу), 'act_cancel' (снять задачу),
                'act_expire' (провалить задачу),
                'act_renew' (возобновить задачу))
        output:
            None
        """
        if (Action not in self._ActionType):
            raise AttributeError('Invalid parameter value')

        uri = '{0}action.api'.format(self.TASK)
        params = {'Id': str(Id), 'Action': Action}
        return self._GetData(uri, params)

    def TaskAvailableActions(self, Id):
        """
        input:
            Id: integer # ID задачи. Обязательный параметр
        output:
            actions: array

        act_accept_task - исполнитель принимает задачу
        act_reject_task - исполнитель отклоняет задачу
        act_accept_work - постановщик принимает выполненную задачу
        act_reject_work - постановщик отклоняет выполненную задачу
        act_done - исполнитель заканчивает работу, задача условно завершена
        act_pause - временно приостановить выполнение задачи
        act_resume - продолжить выполнение приостановленной задачи
        act_cancel - отменить задачу
        act_expire - провалить задачу
        act_renew - принять ранее отклоненную задачу
        """
        uri = '{0}availableActions.api?Id={1}'.format(self.TASK, Id)
        return self._GetData(uri)

    def TaskMarkAsFavorite(self, Id, Value=True):
        """
        input:
            Id: integer # ID задачи. Обязательный параметр
            Value: integer = (1 (пометить как избранное),
                0 (убрать из избранного))
        output:
            None
        """
        if Value:
            self.FavoriteAdd('task', Id)
        else:
            self.FavoriteRemove('task', Id)

    def Projects(self,
                 Folder='all',
                 Status='any',
                 FavoritesOnly=False,
                 Search=''):
        """
        input:
            Folder='all': string = ('incoming' (входящие),
                'responsible' (ответственный), 'executor' (соисполнитель),
                'owner' (исходящие), 'auditor' (аудируемые),
                'all' (все)) # Папка
            Status='any': string = ('actual' (актуальные), 'inprocess' (в процессе),
                'new' (новые), 'overdue' (просроченные),
                'done' (условно завершенные), 'delayed' (отложенные),
                'completed' (завершенные), 'failed' (проваленные),
                'any' (любые)) # Статус
            FavoritesOnly=0: integer = (0, 1) # Только избранное
            Search='': string = 'любая строка' # Строка поиска
        output:
            projects<array>:
                Id: integer # ID проекта
                Name: string # Название
                Status: string # Статус
                Deadline: datetime # Дедлайн
                Owner: object(Id, Name) # Владелец (сотрудник)
                Responsible: object(Id, Name) # Менеджер (сотрудник)
                Severity: object(Id, Name) # Важность
                SuperProject: object(Id, Name) # Надпроект
                Favorite: integer # В избранном
                TimeCreated: datetime # Время создания
        """
        if (Folder not in self._FolderType) or (Status
                                                not in self._StatusType):
            raise AttributeError('Invalid parameter value')

        uri = '{0}list.api?Folder={1}&Status={2}&FavoritesOnly={3}&Search={4}'
        uri = uri.format(self.PROJECT, Folder, Status, int(FavoritesOnly),
                         Search)
        return self._GetData(uri)

    def ProjectCard(self, Id):
        """
        input:
            Id: integer # ID проекта. Обязательный параметр
        output:
            project:
                Id: integer # ID проекта
                Name: string # Название
                Statement: string # Описание проекта
                Status: string # Статус
                Deadline: datetime # Дедлайн
                DeadlineType: string # Тип дедлайна
                Owner: object(Id, Name) # Создатель (сотрудник)
                Responsible: object(Id, Name) # Менеджер (сотрудник)
                Executors: array<object> (Id, Name) # Команда проекта
                    (сотрудники)
                Auditors: array<object> (Id, Name) # Аудиторы (сотрудники)
                Severity: object(Id, Name) # Важность
                SuperProject: object(Id, Name) # Надпроект
                SubProjects: array<object>(Id, Name, Owner, Responsible,
                    Deadline, Favorite (версия 2011.02+)) # Подпроекты
                Tasks: array<object> (Id, Name, Owner, Responsible, Deadline,
                    Favorite (версия 2011.02+)) # Задачи проекта
                TimeCreated: datetime # Время создания
                Customer: object(Id, Name, Status, Type) # Заказчик
                    (код, название, статус, тип)
        """
        uri = '{0}card.api?Id={1}'.format(self.PROJECT, Id)
        return self._GetData(uri)

    def ProjectCreate(self, **kwargs):
        """
        input:
            kwargs:
                Model[Name]: string # Название
                Model[Deadline]: datetime # Дедлайн (дата со временем)
                Model[DeadlineDate]: date # Дедлайн (только дата)
                Model[DeadlineType]: string # Тип дедлайна
                Model[Responsible]: integer # Код менеджера
                Model[Executors]: array<integer> # Коды участников проекта
                Model[Auditors]: array<integer> # Коды аудиторов
                Model[Severity]: integer # Код важности
                Model[SuperProject]: integer # Код надпроекта
                Model[Customer]: integer # Код заказчика
                Model[Statement]: string # Описание проекта
        output:
            Id: integer # ID проекта
            Name: string # Название проекта

        У сотрудника может не быть прав на создание проекта. В этом случае команда вернет 403-ю ошибку и
        следующий ответ:
        {
          "status":
          {
            "code":"error",
            "message":"You can not create projects"
          }
        }
        Таким образом, эту команду можно использовать не только для создания проекта,
        но и для проверки наличия прав на создание проекта
        (например, чтобы решить, показывать в приложении кнопку "Создать проект" или нет).
        """
        uri = '{0}create.api'.format(self.PROJECT)
        return self._GetData(uri, kwargs)

    def ProjectEdit(self, Id, **kwargs):
        """
        input:
            Id: integer # ID проекта. Обязательный параметр
            kwargs:
                Model[Name]: string # Название
                Model[Deadline]: datetime # Дедлайн (дата со временем)
                Model[DeadlineDate]: date # Дедлайн (только дата)
                Model[DeadlineType]: string # Тип дедлайна
                Model[Owner]: integer # Код постановщика
                Model[Responsible]: integer # Код менеджера
                Model[Executors]: array<integer> # Коды участников проекта
                Model[Auditors]: array<integer> # Коды аудиторов
                Model[Severity]: integer # Код важности
                Model[SuperProject]: integer # Код надпроекта
                Model[Customer]: integer # Код заказчика
                Model[Statement]: string # Описание проекта
        output:
            None
        """
        uri = '{0}edit.api'.format(self.PROJECT)
        kwargs['Id'] = str(Id)
        self._GetData(uri, kwargs)

    def ProjectAction(self, Id, Action):
        """
        input:
            Id: integer # ID проекта. Обязательный параметр
            Action: string = ('act_accept_work' (принять работу),
                'act_reject_work' (отклонить работу),
                'act_done' (завершить проект), 'act_pause' (поставить на паузу),
                'act_resume' (возобновить проект), 'act_cancel' (снять проект),
                'act_expire' (провалить проект),
                'act_renew' (возобновить проект))
        output:
            None
        """
        if (Action not in self._ActionType):
            raise AttributeError('Invalid parameter value')

        uri = '{0}action.api'.format(self.PROJECT)
        params = {'Id': str(Id), 'Action': Action}
        return self._GetData(uri, params)

    def ProjectAvailableActions(self, Id):
        """
        input:
            Id: integer # ID проекта. Обязательный параметр
        output:
            actions: array

        actions:
            act_accept_work - постановщик принимает выполненный проект
            act_reject_work - постановщик отклоняет выполненный проект
            act_done - исполнитель заканчивает работу, проект условно завершен
            act_pause - временно приостановить выполнение проекта
            act_resume - продолжить выполнение приостановленного проекта
            act_cancel - отменить проект
            act_expire - провалить проект
            act_renew - открыть проект заново
        """
        uri = '{0}availableActions.api?Id={1}'.format(self.PROJECT, Id)
        return self._GetData(uri)

    def ProjectMarkAsFavorite(self, Id, Value=True):
        """
        input:
            Id: integer # ID проекта. Обязательный параметр
            Value: integer = (1 (пометить как избранное),
                0 (убрать из избранного))
        output:
            None
        """
        if Value:
            self.FavoriteAdd('project', Id)
        else:
            self.FavoriteRemove('project', Id)

    def Severities(self):
        """
        input:
            None
        output:
            Id: integer # ID важности
            Name: string # Название
        """
        uri = '{0}list.api'.format(self.SEVERITY)
        return self._GetData(uri)

    def Employees(self, Department=0, OrderBy='name', OrderDir='asc'):
        """
        input:
            Department=0: integer # Id отдела
            OrderBy='name': string = ('name', 'department',
                'position') # Параметр для сортировки
            OrderDir='asc': string = ('asc', 'desc') # Направление сортировки
        output:
            employees<array>:
                Id: integer # ID сотрудника
                Name: string # Полное имя
                LastName: string # Фамилия
                FirstName: string # Имя
                MiddleName: string # Отчество
                Position: object(Id, Name) # Должность
                Department: object(Id, Name) # Отдел
                Phones: array # Телефоны
                Email: string # E-mail
                Status: object(Id, Name) # Статус
                TimeCreated: datetime # Время создания
        """
        uri = '{0}list.api?Department={1}&OrderBy={2}&OrderDir={3}'
        uri = uri.format(self.EMPLOYEE, Department, OrderBy, OrderDir)
        return self._GetData(uri)

    def EmployeeCard(self, Id):
        """
        input:
            Id: integer # ID сотрудника
        output:
            employee:
                Id: integer # ID сотрудника
                Name: string # Полное имя
                LastName: string # Фамилия
                FirstName: string # Имя
                MiddleName: string # Отчество
                Gender: string # Пол
                Position: object(Id, Name) # Должность
                Department: object(Id, Name) # Отдел
                Birthday: date # Дата рождения
                HideMyBirthday: boolean # Скрывать дату рождения
                Age: integer # Возраст
                Phones: array # Телефоны
                Email: string # E-mail
                Icq: string # ICQ
                Skype: string # Skype
                Jabber: string # Jabber
                Address: object(Id, City, Street, House) # Адрес
                Behaviour: string # График работы
                Inn: string # ИНН
                PassportData: string # Паспортные данные
                AboutMe: string # О себе
                ChiefsWithoutMe: array<object>(Id, Name) # Начальники
                SubordinatesWithoutMe: array<object>(Id, Name) # Подчиненные
                Coordinators: array<object>(Id, Name) # Координаторы
                Status: object(Id, Name) # Статус
                AppearanceDay: date # Дата принятия на работу
                FireDay: date # Дата увольнения
                TimeCreated: datetime # Время создания
                Avatar: string # Адрес аватара сотрудника
                Photo: string # Адрес большого фото сотрудника
        """
        uri = '{0}card.api?Id={1}'.format(self.EMPLOYEE, Id)
        return self._GetData(uri)

    def EmployeeCreate(self, **kwargs):
        """
        input:
            kwargs:
                Model[LastName]: string # Фамилия
                Model[FirstName]: string # Имя
                Model[MiddleName]: string # Отчество
                Model[Gender]: string = ('male', 'femail') # Пол
                Model[Position]: string # Должность. Обязательный параметр
                Model[Birthday]: date # Дата рождения
                Model[HideMyBirthday]: boolean # Скрывать дату рождения
                Model[Email]: string # E-mail
                Model[Icq]: string # ICQ
                Model[Skype]: string # Skype
                Model[Jabber]: string # Jabber
                Model[Behaviour]: string # График работы
                Model[PassportData]: string # Паспортные данные
                Model[Inn]: string # ИНН
                Model[AboutMe]: string # О себе
                Model[Status]: string = ('in-office', 'out-of-office') # Статус
                Model[AppearanceDay]: date # Дата принятия на работу
                Address[City]: string # Город
                Address[Street]: string # Улица
                Address[House]: string # Дом
        output:
            Id: integer # ID сотрудника
            Name: string # Имя сотрудника
        """
        uri = '{0}create.api'.format(self.EMPLOYEE)
        return self._GetData(uri, kwargs)

    def EmployeeEdit(self, Id, **kwargs):
        """
        input:
            Id: integer # ID сотрудника. Обязательный параметр
            kwargs:
                Model[LastName]: string # Фамилия
                Model[FirstName]: string # Имя
                Model[MiddleName]: string # Отчество
                Model[Gender]: string = ('male', 'femail') # Пол
                Model[Position]: string # Должность
                Model[Birthday]: date # Дата рождения
                Model[HideMyBirthday]: boolean # Скрывать дату рождения
                Model[Email]: string # E-mail
                Model[Icq]: string # ICQ
                Model[Skype]: string # Skype
                Model[Jabber]: string # Jabber
                Model[Behaviour]: string # График работы
                Model[PassportData]: string # Паспортные данные
                Model[Inn]: string # ИНН
                Model[AboutMe]: string # О себе
                Model[Status]: string = ('in-office', 'out-of-office') # Статус
                Model[AppearanceDay]: date # Дата принятия на работу
                Address[City]: string # Город
                Address[Street]: string # Улица
                Address[House]: string # Дом
        output:
            None
        """
        uri = '{0}edit.api'.format(self.EMPLOYEE)
        kwargs['Id'] = str(Id)
        self._GetData(uri, kwargs)

    def EmployeeAvailableActions(self, Id):
        """
        input:
            Id: integer # ID сотрудника. Обязательный параметр
        output:
            actions: array

        actions:
            act_can_fire - уволить
            act_edit - редактировать
        """
        uri = '{0}availableActions.api?Id={1}'.format(self.EMPLOYEE, Id)
        return self._GetData(uri)

    def Departments(self):
        """
        input:
            None
        output:
            departments<array>:
                Id: integer # ID отдела
                Name: string # Название отдела
                Head: object(Id, Name) # Начальник отдела
                Employees: array<object(Id, Name)> # Список сотрудников отдела
                EmployeesCount: integer # Количество сотрудников в отделе
        """
        uri = '{0}list.api'.format(self.DEPARTMENT)
        return self._GetData(uri)

    def Comments(self, SubjectType, SubjectId, Order='asc'):
        """
        input:
            SubjectType: string = ('task' (задача),
                'project' (проект)) # Тип комментируемого объекта
            SubjectId: integer # ID комментируемого объекта
            Order='asc': string = ('asc' (по возрастанию), 'desc' (по убыванию))
                # Направление сортировки по дате (по умолчанию asc)
        output:
            comments<array>:
                Id: integer # ID комментария
                Text: string # Текст комментария
                Work: integer # Кол-во потраченных минут, которое приплюсовано
                    к комментируемому объекту (задаче или проекту)
                WorkDate: date # Дата, на которую списаны потраченные часы
                TimeCreated: datetime # Время создания
                Author: object(Id, Name) # Автор комментария (сотрудник)
                Avatar: string # Адрес аватара автора
        """
        if (SubjectType not in self._SubjectType) or \
            (Order not in self._OrderType):
            raise AttributeError('Invalid parameter value')

        uri = '{0}list.api?SubjectType={1}&SubjectId={2}&Order={3}'
        uri = uri.format(self.COMMENT, SubjectType, SubjectId, Order)
        return self._GetData(uri)

    def CommentCreate(self, SubjectType, SubjectId, **kwargs):
        """
        input:
            SubjectType: string = ('task' (задача),
                'project' (проект)) # Тип комментируемого объекта
            SubjectId: integer # ID комментируемого объекта
            kwargs:
                Model[Text]: string # Текст комментария
                Model[Work]: integer # Кол-во потраченных часов, которое
                    приплюсуется к комментируемому объекту (задача или проект)
                Model[WorkDate]: date # Дата, на которую списывать
                    потраченные часы
                Model[Attaches]: array # Приложенный файл,
                    должен передаваться POST-запросом
                Model[Attaches][Content]: string # Данные(контент файла),
                    закодированные с использованием MIME base64
                Model[Attaches][Name]: string # Имя файла (будет фигурировать
                    при выводе комментария)

        output:
            Id: integer # ID комментария
            Text: string # Текст комментария
            Work: integer # Кол-во потраченных минут, которое приплюсуется
                к комментируемому объекту (задача или проект)
            WorkDate: date # Дата, на которую списывать потраченные часы
            TimeCreated: datetime # Время создания
        """
        if SubjectType not in self._SubjectType:
            raise AttributeError('Invalid parameter value')

        uri = '{0}create.api'.format(self.COMMENT)
        kwargs['SubjectId'] = str(SubjectId)
        kwargs['SubjectType'] = SubjectType
        return self._GetData(uri, kwargs)

    def Favorites(self):
        """
        input:
            None
        output:
            Tasks<array>:
                Tasks: array # Список задач, см. структуру в "Список задач"
                Projects: array # Список проектов,
                    см. структуру в "Список проектов"
        """
        uri = '{0}list.api'.format(self.FAVORITE)
        return self._GetData(uri)

    def FavoriteAdd(self, SubjectType, SubjectId):
        """
        input:
            SubjectType: string = ('task' (задача),
                'project' (проект)) # Тип объекта
            SubjectId: integer # ID объекта
        output:
            None
        """
        if SubjectType not in self._SubjectType:
            raise AttributeError('Invalid parameter value')

        uri = '{0}add.api'.format(self.FAVORITE)
        params = {'SubjectId': str(SubjectId), 'SubjectType': SubjectType}
        self._GetData(uri, params)

    def FavoriteRemove(self, SubjectType, SubjectId):
        """
        input:
            SubjectType: string = ('task' (задача),
                'project' (проект)) # Тип объекта
            SubjectId: integer # ID объекта
        output:
            None
        """
        if SubjectType not in self._SubjectType:
            raise AttributeError('Invalid parameter value')

        uri = '{0}remove.api'.format(self.FAVORITE)
        params = {'SubjectId': str(SubjectId), 'SubjectType': SubjectType}
        self._GetData(uri, params)

    def Search(self, qs):
        """
        input:
            qs: string # Текст для поиска
            # Если параметр qs не указан либо пустой, то будет возвращена ошибка
            # "Empty query". Если же, результатов соответствующих запросу
            # не найдено, то в выходных данных будет возвращена ошибка
            # "No results".
        output:
            Employees: array # Список сотрудников,
                см. структуру в "Список сотрудников"
            Tasks: array # Список задач, см. структуру в "Список задач"
            Projects: array # Список проектов, см. структуру в "Список проектов"
        """
        uri = '{0}quick.api'.format(self.SEARCH)
        params = {'qs': qs}
        return self._GetData(uri, params)

    def Notifications(self):
        """
        input:
            None
        output:
            notifications<array>:
                Id: integer # ID уведомления
                Subject: object(Id,Name,Type) # Предмет уведомления
                    (см. пояснение ниже)
                Content: string или object(Subject,Text,Author) # Содержимое
                    уведомления (см. пояснение ниже)
                TimeCreated: datetime # Время создания уведомления

            # см. http://wiki.megaplan.ru/API_notifications

        Subject - это модель данных, с которой связано уведомление
            (задача, проект, сотрудник или комментарий). Если, например,
            уведомление о том, что поставлена задача, то в Subject будет
            идентификатор задачи. Subject содержит следующие аттрибуты:
                Id - идентификатор модели
                Name - название модели
                Type - тип модели (task/project/employee/comment).
        Структура Content зависит от типа Subject. Для всех типов, кроме
            комментариев, это простой текст уведомления. В случае
            с комментариями Content содержит следующие аттрибуты:
                Subject - предмет комментирования (задача или проект)
                    с вложенной структурой, аналогичной Subject
                    в самом уведомлении
                Text - текст комментария
                Author - автор комментария (Id и Name)
        """
        uri = '{0}notifications.api'.format(self.INFORMER)
        return self._GetData(uri)

    def NotificationDeactivate(self, Id):
        """
        input:
            Id: integer # ID уведомления. Обязательный параметр
        output:
            None
        """
        uri = '{0}deactivateNotification.api'.format(self.INFORMER)
        params = {'Id': str(Id)}
        self._GetData(uri, params)

    def Approvals(self):
        """
        input:
            None
        output:
            Tasks: array # Список задач, см. структуру в "Список задач"
            Projects: array # Список проектов, см. структуру в "Список проектов"
        """
        uri = '{0}approvals.api'.format(self.INFORMER)
        return self._GetData(uri)

    def TodoLists(self):
        """
        input:
            None
        output:
            Id: integer # Id списка дел
            Name: string # Название списка дел
            TodoCount: integer # Количество незавершенных дел в списке
        """
        uri = '{0}list.api'.format(self.TODOLIST)
        return self._GetData(uri)

    def TodoListCreate(self, Name):
        """
        input:
            Name: string # Название списка дел
        output:
            Id: integer # Id созданного списка
        """
        uri = '{0}create.api'.format(self.TODOLIST)
        params = {'Name': Name}
        return self._GetData(uri, params)

    def TodoListEdit(self, Id, Name):
        """
        input:
            Id: integer # Id списка дел
            Name: string # Новое имя списка
        output:
            Id: integer # Id измененного списка
        """
        uri = '{0}edit.api'.format(self.TODOLIST)
        params = {'Id': Id, 'Name': Name}
        return self._GetData(uri, params)

    def TodoListDelete(self, Id):
        """
        input:
            Id: integer # Id списка дел
        output:
            Id: integer # Id удаленного списка
        """
        uri = '{0}delete.api'.format(self.TODOLIST)
        params = {'Id': Id}
        return self._GetData(uri, params)

    def Events(self):
        """
        input:
            None
        output:
            Id: integer # Id события
            Name: string # Название события
            TimeCreated: datetime # Дата и время создания
            StartTime: datetime# Начало события
            Duration: integer # Продолжительность события
            IsPersonal: boolean # Личное дело?
            EventCategory: string # Категория события
            Participants: array # Список участников
            Contractors: array # Список контрагентов
            HasTodo: boolean # Имеет дела?
            HasCommunication: boolean # Имеет коммуникации?
        """
        uri = '{0}list.api'.format(self.EVENT)
        return self._GetData(uri)

    def FromOnlineStoreCreate(self, CommerceInfo):
        """
        input:
            CommerceInfo: string # Данные в формате CommerceML 2.
        output:
            Deals: array # Идентификаторы сделок, созданные в системе
        """
        uri = '{0}createFromOnlineStore.api'.format(self.DEAL)
        params = {'CommerceInfo': CommerceInfo}
        return self._GetData(uri, params)
예제 #2
0
class Direct(object):
    _VersionAPI = 4
    HOST = 'https://soap.direct.yandex.ru/json-api/v4/'
    Locale = 'en'
    _UserAgent = 'yadirectpy'

    @property
    def UserAgent(self):
        return self._UserAgent

    @UserAgent.setter
    def UserAgent(self, user_agent):
        self._UserAgent = user_agent

    @property
    def VersionAPI(self):
        return self._VersionAPI

    @VersionAPI.setter
    def VersionAPI(self, version_api):
        self._VersionAPI = version_api
        self.HOST = 'https://soap.direct.yandex.ru/json-api/v%d/' % version_api

    def __init__(self, key_file=None, cert_file=None):
        self._client = APIClient(key_file, cert_file)
        self._client.UserAgent = self._UserAgent
        self._data = ''

    def _GetResponseObject(f):
        def wrapper(self):
            obj = JSON2Obj(self._data)
            if hasattr(obj, 'error_code'):
                raise APIException(obj.error_code, obj.error_str,
                                   obj.error_detail)
            return f(self, obj)

        return wrapper

    def _GetHeaders(self):
        header = {
            'User-Agent': self._UserAgent,
            'Accept': 'application/json',
            'Accept-Language': 'ru,en-us;q=0.7,en;q=0.3',
            'Accept-Encoding': 'gzip,deflate',
            'Accept-Charset': 'utf-8;q=0.7,*;q=0.7',
            'Keep-Alive': '300',
            'Connection': 'keep-alive'
        }
        return header

    @_GetResponseObject
    def _ResponseHandle(self, obj):
        return obj

    def _GetData(self, method, uri, params={}):
        headers = self._GetHeaders()
        self._data = self._client.Request(method,
                                          uri,
                                          params=params,
                                          headers=headers)
        return self._ResponseHandle()

    def GetData(self):
        return self._data

    def _GetParams(self, method, params):
        return {'method': method, 'param': params, 'locale': self.Locale}

    def _Method(self, **kwargs):
        if kwargs.get('params'):
            params = self._GetParams(self.method, kwargs['params'])
        else:
            params = self._GetParams(self.method, kwargs)
        return self._GetData('POST', self.HOST,
                             json.dumps(params, ensure_ascii=False))

    def __getattr__(self, attr):
        self.method = attr
        return self._Method