Exemplo n.º 1
0
 def update_message(self,
                    message_id,
                    category_id,
                    title,
                    body,
                    extended_body,
                    use_textile=False,
                    private=False,
                    notify=None):
     """
     Updates an existing message, optionally sending notifications to a
     selected list of people. Note that you can also upload files using
     this function, but you have to format the request as
     multipart/form-data. (See the ruby Basecamp API wrapper for an example
     of how to do this.)
     """
     path = '/msg/update/%u' % message_id
     req = ET.Element('request')
     req.append(
         self._create_message_post_elem(category_id,
                                        title,
                                        body,
                                        extended_body,
                                        use_textile=False,
                                        private=False))
     if notify is not None:
         for person_id in notify:
             ET.SubElement(req, 'notify').text = str(int(person_id))
     return self._request(path, req)
Exemplo n.º 2
0
 def _create_milestone_elem(self, title, deadline, party_id, notify):
     milestone = ET.Element('milestone')
     ET.SubElement(milestone, 'title').text = str(title)
     ET.SubElement(milestone, 'deadline', type='date').text = str(deadline)
     ET.SubElement(milestone, 'responsible-party').text = str(party_id)
     ET.SubElement(milestone, 'notify').text = str(bool(notify)).lower()
     return milestone
Exemplo n.º 3
0
 def create_comment(self, post_id, body):
     """
     Create a new comment, associating it with a specific message.
     """
     path = '/msg/create_comment'
     req = ET.Element('request')
     comment = ET.SubElement(req, 'comment')
     ET.SubElement(comment, 'post-id').text = str(int(post_id))
     ET.SubElement(comment, 'body').text = str(body)
     return self._request(path, req)
Exemplo n.º 4
0
 def update_comment(self, comment_id, body):
     """
     Update a specific comment. This can be used to edit the content of an
     existing comment.
     """
     path = '/msg/update_comment'
     req = ET.Element('request')
     ET.SubElement(req, 'comment_id').text = str(int(comment_id))
     comment = ET.SubElement(req, 'comment')
     ET.SubElement(comment, 'body').text = str(body)
     return self._request(path, req)
Exemplo n.º 5
0
 def list_milestones(self, project_id, find=None):
     """
     This lets you query the list of milestones for a project. You can
     either return all milestones, or only those that are late, completed,
     or upcoming.
     """
     path = '/projects/%u/milestones/list' % project_id
     req = ET.Element('request')
     if find is not None:
         ET.SubElement(req, 'find').text = str(find)
     return self._request(path, req)
Exemplo n.º 6
0
 def move_todo_item(self, item_id, to):
     """
     Changes the position of an item within its parent list. It does not
     currently support reparenting an item. Position 1 is at the top of the
     list. Moving an item beyond the end of the list puts it at the bottom
     of the list.
     """
     path = '/todos/move_item/%u' % item_id
     req = ET.Element('request')
     ET.SubElement(req, 'to').text = str(int(to))
     return self._request(path, req)
Exemplo n.º 7
0
 def todo_lists(self, project_id, complete=None):
     """
     This will return the metadata for all of the lists in a given project.
     You can further constrain the query to only return those lists that
     are "complete" (have no uncompleted items) or "uncomplete" (have
     uncompleted items remaining).
     """
     path = '/projects/%u/todos/lists' % project_id
     req = ET.Element('request')
     if complete is not None:
         ET.SubElement(req, 'complete').text = str(bool(complete)).lower()
     return self._request(path, req)
Exemplo n.º 8
0
 def update_todo_item(self, item_id, content, party_id=None, notify=False):
     """
     Modifies an existing item. The values work much like the "create item"
     operation, so you should refer to that for a more detailed explanation.
     """
     path = '/todos/update_item/%u' % item_id
     req = ET.Element('request')
     item = ET.Element('request')
     ET.SubElement(item, 'content').text = str(content)
     if party_id is not None:
         ET.SubElement(req, 'responsible-party').text = str(party_id)
         ET.SubElement(req, 'notify').text = str(bool(notify)).lower()
     return self._request(path, req)
Exemplo n.º 9
0
 def move_todo_list(self, list_id, to):
     """
     This allows you to reposition a list relative to the other lists in
     the project. A list with position 1 will show up at the top of the
     page. Moving lists around lets you prioritize. Moving a list to a
     position less than 1, or more than the number of lists in a project,
     will force the position to be between 1 and the number of lists
     (inclusive).
     """
     path = '/todos/move_list/%u' % list_id
     req = ET.Element('request')
     ET.SubElement(req, 'to').text = str(int(to))
     return self._request(path, req)
Exemplo n.º 10
0
 def message_archive(self, project_id, category_id=None):
     """
     This will return a summary record for each message in a project. If
     you specify a category_id, only messages in that category will be
     returned. (Note that a summary record includes only a few bits of
     information about a post, not the complete record.)
     """
     path = '/projects/%u/msg/archive' % project_id
     req = ET.Element('request')
     ET.SubElement(req, 'project-id').text = str(int(project_id))
     if category_id is not None:
         ET.SubElement(req, 'category-id').text = str(int(category_id))
     return self._request(path, req)
Exemplo n.º 11
0
 def create_todo_list(self,
                      project_id,
                      milestone_id=None,
                      private=None,
                      tracked=False,
                      name=None,
                      description=None,
                      template_id=None):
     """
     This will create a new, empty list. You can create the list
     explicitly, or by giving it a list template id to base the new list
     off of.
     """
     path = '/projects/%u/todos/create_list' % project_id
     req = ET.Element('request')
     if milestone_id is not None:
         ET.SubElement('milestone-id').text = str(milestone_id)
     if private is not None:
         ET.SubElement('private').text = str(bool(private)).lower()
     ET.SubElement('tracked').text = str(bool(tracked)).lower()
     if name is not None:
         ET.SubElement('name').text = str(name)
         ET.SubElement('description').text = str(description)
     if template_id is not None:
         ET.SubElement('use-template').text = 'true'
         ET.SubElement('template-id').text = str(int(template_id))
     return self._request(path, req)
Exemplo n.º 12
0
 def comments(self, message_id):
     """
     Return the list of comments associated with the specified message.
     """
     path = '/msg/comments/%u' % message_id
     req = ET.Element('request')
     return self._request(path, req)
Exemplo n.º 13
0
 def create_todo_item(self, list_id, content, party_id=None, notify=False):
     """
     This call lets you add an item to an existing list. The item is added
     to the bottom of the list. If a person is responsible for the item,
     give their id as the party_id value. If a company is responsible,
     prefix their company id with a 'c' and use that as the party_id value.
     If the item has a person as the responsible party, you can use the
     notify key to indicate whether an email should be sent to that person
     to tell them about the assignment.
     """
     path = '/todos/create_item/%u' % list_id
     req = ET.Element('request')
     ET.SubElement(req, 'content').text = str(content)
     if party_id is not None:
         ET.SubElement(req, 'responsible-party').text = str(party_id)
         ET.SubElement(req, 'notify').text = str(bool(notify)).lower()
     return self._request(path, req)
Exemplo n.º 14
0
 def messages(self):
     if self.cache['messages']: return self.cache['messages']
     message_xml = self.bc.message_archive(self.id)
     messages = []
     for post in ET.fromstring(message_xml).findall("post"):
         messages.append(Message(post))
     self.cache['messages'] = messages
     return self.cache['messages']
Exemplo n.º 15
0
 def messages(self):
     if self.cache['messages']: return self.cache['messages']
     message_xml = self.bc.message_archive(self.id)
     messages = []
     for post in ET.fromstring(message_xml).findall("post"):
         messages.append(Message(post))
     self.cache['messages'] = messages
     return self.cache['messages']
Exemplo n.º 16
0
def parse_basecamp_xml(xml_object):
    if hasattr(xml_object, 'getchildren'):
        nodes = xml_object.getchildren()
    else:
        nodes = ET.fromstring(xml_object).getchildren()
        
    parsed = parse_tree(nodes)
    return parsed
Exemplo n.º 17
0
 def people(self):
     '''Dictionary of people on the project, keyed by id'''
     if self.cache['people']: return self.cache['people']
     people_xml = self.bc.people_within_project(self.id)
     for person_node in ET.fromstring(people_xml).findall('person'):
         p = Person(person_node)
         self.cache['people'][p.id] = p
     return self.cache['people']
Exemplo n.º 18
0
 def people(self):
     '''Dictionary of people on the project, keyed by id'''
     if self.cache['people']: return self.cache['people']
     people_xml = self.bc.people_within_project(self.id)
     for person_node in ET.fromstring(people_xml).findall('person'):
         p = Person(person_node)
         self.cache['people'][p.id] = p
     return self.cache['people']
Exemplo n.º 19
0
def parse_basecamp_xml(xml_object):
    if hasattr(xml_object, 'getchildren'):
        nodes = xml_object.getchildren()
    else:
        nodes = ET.fromstring(xml_object).getchildren()

    parsed = parse_tree(nodes)
    return parsed
Exemplo n.º 20
0
 def __cache_result(self, path, data, result):
     if data:
         data = ET.tostring(data)
         if not self.__test_responses['POST'].has_key(path):
             self.__test_responses['POST'][path] = {}
         self.__test_responses['POST'][path][data] = result
     else:
         self.__test_responses['GET'][path] = result
     return result
Exemplo n.º 21
0
 def __cache_result(self, path, data, result):
     if data:
         data = ET.tostring(data)
         if not self.__test_responses["POST"].has_key(path):
             self.__test_responses["POST"][path] = {}
         self.__test_responses["POST"][path][data] = result
     else:
         self.__test_responses["GET"][path] = result
     return result
Exemplo n.º 22
0
 def todo_lists(self):
     if self.cache['todo_lists']: return self.cache['todo_lists']
     todo_lists_xml = self.bc.todo_lists(self.id)
     todo_lists = {}
     for node in ET.fromstring(todo_lists_xml).findall("todo-list"):
         the_list = ToDoList(node)
         todo_lists[the_list.name] = the_list
     self.cache['todo_lists'] = todo_lists
     return self.cache['todo_lists']
Exemplo n.º 23
0
 def todo_lists(self):
     if self.cache['todo_lists']: return self.cache['todo_lists']
     todo_lists_xml = self.bc.todo_lists(self.id)
     todo_lists = {}
     for node in ET.fromstring(todo_lists_xml).findall("todo-list"):
         the_list = ToDoList(node)
         todo_lists[the_list.name] = the_list
     self.cache['todo_lists'] = todo_lists
     return self.cache['todo_lists']
Exemplo n.º 24
0
 def create_message(self,
                    project_id,
                    category_id,
                    title,
                    body,
                    extended_body,
                    use_textile=False,
                    private=False,
                    notify=None,
                    attachments=None):
     """
     Creates a new message, optionally sending notifications to a selected
     list of people. Note that you can also upload files using this
     function, but you need to upload the files first and then attach them.
     See the description at the top of this document for more information.
     """
     path = '/projects/%u/msg/create' % project_id
     req = ET.Element('request')
     req.append(
         self._create_message_post_elem(category_id,
                                        title,
                                        body,
                                        extended_body,
                                        use_textile=False,
                                        private=False))
     if notify is not None:
         for person_id in notify:
             ET.SubElement(req, 'notify').text = str(int(person_id))
     # TODO: Implement attachments.
     if attachments is not None:
         raise NotSupportedErr('Attachments are currently not implemented.')
     ##for attachment in attachments:
     ##    attms = ET.SubElement(req, 'attachments')
     ##    if attachment['name']:
     ##        ET.SubElement(attms, 'name').text = str(attachment['name'])
     ##    file_ = ET.SubElement(attms, 'file')
     ##    ET.SubElement(file_, 'file').text = str(attachment['temp_id'])
     ##    ET.SubElement(file_, 'content-type').text \
     ##        = str(attachment['content_type'])
     ##    ET.SubElement(file_, 'original-filename').text \
     ##        = str(attachment['original_filename'])
     return self._request(path, req)
Exemplo n.º 25
0
 def create_milestones(self, project_id, milestones):
     """
     With this function you can create multiple milestones in a single
     request. See the "create" function for a description of the individual
     fields in the milestone.
     """
     path = '/projects/%u/milestones/create' % project_id
     req = ET.Element('request')
     for milestone in milestones:
         req.append(self._create_milestone_elem(*milestone))
     return self._request(path, req)
Exemplo n.º 26
0
 def create_milestone(self, project_id, title, deadline, party_id, notify):
     """
     Creates a single milestone. To create multiple milestones in a single
     call, see the "create (batch)" function. To make a company responsible
     for the milestone, prefix the company id with a "c".
     """
     path = '/projects/%u/milestones/create' % project_id
     req = ET.Element('request')
     req.append(
         self._create_milestone_elem(title, deadline, party_id, notify))
     return self._request(path, req)
Exemplo n.º 27
0
 def comments(self):
     '''Looks through the last 3 messages and returns those comments.'''
     if self.cache['comments']: return self.cache['comments']
     comments = []
     for message in self.messages[0:3]:
         comment_xml = self.bc.comments(message.id)
         for comment_node in ET.fromstring(comment_xml).findall("comment"):
             comments.append(Comment(comment_node))
     comments.sort()
     comments.reverse()
     self.cache['comments'] = comments
     return self.cache['comments']
Exemplo n.º 28
0
 def comments(self):
     '''Looks through the last 3 messages and returns those comments.'''
     if self.cache['comments']: return self.cache['comments']
     comments = []
     for message in self.messages[0:3]:
         comment_xml = self.bc.comments(message.id)
         for comment_node in ET.fromstring(comment_xml).findall("comment"):
             comments.append(Comment(comment_node))
     comments.sort()
     comments.reverse()
     self.cache['comments'] = comments
     return self.cache['comments']
Exemplo n.º 29
0
    def milestones(self):
        '''Array of all milestones'''
        if self.cache['milestones']: return self.cache['milestones']
        milestone_xml = self.bc.list_milestones(self.id)
        milestones = []
        for node in ET.fromstring(milestone_xml).findall("milestone"):
            milestones.append(Milestone(node))

        milestones.sort()
        milestones.reverse()
        self.cache['milestones'] = milestones
        return self.cache['milestones']
Exemplo n.º 30
0
    def milestones(self):
        '''Array of all milestones'''
        if self.cache['milestones']: return self.cache['milestones']
        milestone_xml = self.bc.list_milestones(self.id)
        milestones = []
        for node in ET.fromstring(milestone_xml).findall("milestone"):
            milestones.append(Milestone(node))

        milestones.sort()
        milestones.reverse()
        self.cache['milestones'] = milestones
        return self.cache['milestones']
Exemplo n.º 31
0
 def time_entries(self, start_date=None, end_date=None):
     '''Array of all time entries'''
     if self.cache['time_entries']: return self.cache['time_entries']
     if not start_date:
         start_date = datetime.date(1900, 1, 1)
     if not end_date:
         end_date = datetime.date.today()
     time_entry_xml = self.bc.list_time_entries(self.id, start_date, end_date)
     time_entries = []
     for entry in ET.fromstring(time_entry_xml).findall("time-entry"):
         time_entries.append(TimeEntry(entry))
     self.cache['time_entries'] = time_entries
     return self.cache['time_entries']
Exemplo n.º 32
0
 def _request(self, path, data=None):
     if hasattr(data, 'findall'):
         data = ET.tostring(data)
     #print "***Sending***\n",data
     #req = urllib2.Request(url=self.baseURL + path, data=data)
     #print req.get_method(),req.get_full_url(),req.header_items()
     #return self.opener.open(req).read()
     if data:
         r = requests.post(self.baseURL + path,data=data,headers=dict(self.headers),auth=(self.username,self.password),allow_redirects=True)
     else:
         r = requests.get(self.baseURL + path,headers=dict(self.headers),auth=(self.username,self.password))
     #print "received ",r.status_code,'"%s"'%r.text
     return r
Exemplo n.º 33
0
 def __test_request_local(self, path, data):
     if data:
         data = ET.tostring(data)
         try:
             return self.__test_responses["POST"][path][data]
         except KeyError:
             print "Cache miss: POST %s\n\t%s\n" % (path, data)
             raise
     try:
         return self.__test_responses["GET"][path]
     except KeyError:
         print "Cache miss: GET %s" % (path)
         print "Cache: %s" % (pprint.pformat(self.__test_responses["GET"]))
         raise
Exemplo n.º 34
0
 def __test_request_local(self, path, data):
     if data:
         data = ET.tostring(data)
         try:
             return self.__test_responses['POST'][path][data]
         except KeyError:
             print "Cache miss: POST %s\n\t%s\n" % (path, data)
             raise
     try:
         return self.__test_responses['GET'][path]
     except KeyError:
         print "Cache miss: GET %s" % (path)
         print "Cache: %s" % (pprint.pformat(self.__test_responses['GET']))
         raise
Exemplo n.º 35
0
 def time_entries(self, start_date=None, end_date=None):
     '''Array of all time entries'''
     if self.cache['time_entries']: return self.cache['time_entries']
     if not start_date:
         start_date = datetime.date(1900, 1, 1)
     if not end_date:
         end_date = datetime.date.today()
     time_entry_xml = self.bc.list_time_entries(self.id, start_date,
                                                end_date)
     time_entries = []
     for entry in ET.fromstring(time_entry_xml).findall("time-entry"):
         time_entries.append(TimeEntry(entry))
     self.cache['time_entries'] = time_entries
     return self.cache['time_entries']
Exemplo n.º 36
0
 def update_milestone(self,
                      milestone_id,
                      title,
                      deadline,
                      party_id,
                      notify,
                      move_upcoming_milestones=None,
                      move_upcoming_milestones_off_weekends=None):
     """
     Modifies a single milestone. You can use this to shift the deadline of
     a single milestone, and optionally shift the deadlines of subsequent
     milestones as well.
     """
     path = '/milestones/update/%u' % milestone_id
     req = ET.Element('request')
     req.append(
         self._create_milestone_elem(title, deadline, party_id, notify))
     if move_upcoming_milestones is not None:
         ET.SubElement(req, 'move-upcoming-milestones').text \
             = str(bool()).lower()
     if move_upcoming_milestones_off_weekends is not None:
         ET.SubElement(req, 'move-upcoming-milestones-off-weekends').text \
             = str(bool()).lower()
     return self._request(path, req)
Exemplo n.º 37
0
 def _create_message_post_elem(self,
                               category_id,
                               title,
                               body,
                               extended_body,
                               use_textile=False,
                               private=False):
     post = ET.Element('post')
     ET.SubElement(post, 'category-id').text = str(int(category_id))
     ET.SubElement(post, 'title').text = str(title)
     ET.SubElement(post, 'body').text = str(body)
     ET.SubElement(post, 'extended-body').text = str(extended_body)
     if bool(use_textile):
         ET.SubElement(post, 'use-textile').text = '1'
     if bool(private):
         ET.SubElement(post, 'private').text = '1'
     return post
Exemplo n.º 38
0
 def update_todo_list(self,
                      list_id,
                      name,
                      description,
                      milestone_id=None,
                      private=None,
                      tracked=None):
     """
     With this call you can alter the metadata for a list.
     """
     path = '/todos/update_list/%u' % list_id
     req = ET.Element('request')
     list_ = ET.SubElement('list')
     ET.SubElement(list_, 'name').text = str(name)
     ET.SubElement(list_, 'description').text = str(description)
     if milestone_id is not None:
         ET.SubElement(list_, 'milestone_id').text = str(int(milestone_id))
     if private is not None:
         ET.SubElement(list_, 'private').text = str(bool(private)).lower()
     if tracked is not None:
         ET.SubElement(list_, 'tracked').text = str(bool(tracked)).lower()
     return self._request(path, req)
Exemplo n.º 39
0
 def _request(self, path, data=None):
     if hasattr(data, 'findall'):
         data = ET.tostring(data)
     req = urllib2.Request(url=self.baseURL + path, data=data)
     return self.opener.open(req).read()
Exemplo n.º 40
0
 def _get_project_info(self):
     project_xml = self.bc._request("/projects/%s.xml" % self.id)
     node = ET.fromstring(project_xml)
     self._name = node.findtext("name")
     self._status = node.findtext("status")
     self._last_changed_on = node.findtext("last-changed-on")
Exemplo n.º 41
0
 def _request(self, path, data=None):
     if hasattr(data, 'findall'):
         data = ET.tostring(data)
     req = urllib2.Request(url=self.baseURL + path, data=data)
     return self.opener.open(req).read()
Exemplo n.º 42
0
 def _get_project_info(self):
     project_xml = self.bc._request("/projects/%s.xml" % self.id)
     node = ET.fromstring(project_xml)
     self._name = node.findtext("name")
     self._status = node.findtext("status")
     self._last_changed_on = node.findtext("last-changed-on")