def remove(self, project_id): """Removes project from contact's project list""" url = '{0}/contacts/{1}/projects/{2}.json'.format( self._redmine.url, self._contact_id, project_id) try: return self._redmine.request('delete', url) except ResourceNotFoundError: raise ValidationError( "Attempt to remove contact from a project that doesn't exist" ) except ForbiddenError: raise ValidationError( 'Attempt to remove contact from a project that either has contacts module disabled or is read-only' )
def update(self, resource_id, **fields): """Updates a Resource object by resource id (can be either integer id or string identifier)""" if self.resource_class.query_update is None or self.resource_class.container_update is None: raise ResourceBadMethodError() if not fields: raise ResourceNoFieldsProvidedError for index, upload in enumerate(fields.get('uploads', [])): fields['uploads'][index]['token'] = self.redmine.upload( upload.get('path', '')) formatter = MemorizeFormatter() try: query_update = formatter.format(self.resource_class.query_update, resource_id, **fields) except KeyError as exception: param = str(exception).replace("'", "") if param in self.params: fields[param] = self.params[param] query_update = formatter.format( self.resource_class.query_update, resource_id, **fields) else: raise ValidationError( '{0} argument is required'.format(exception)) url = '{0}{1}'.format(self.redmine.url, query_update) data = { self.resource_class.container_update: self.prepare_params(formatter.unused_kwargs) } return self.redmine.request('put', url, data=data)
def create(self, **fields): """Creates a new resource in Redmine database and returns resource object on success""" if self.resource_class.query_create is None or self.resource_class.container_create is None: raise ResourceBadMethodError() if not fields: raise ResourceNoFieldsProvidedError for index, upload in enumerate(fields.get('uploads', [])): fields['uploads'][index]['token'] = self.redmine.upload( upload.get('path', '')) formatter = MemorizeFormatter() try: url = '{0}{1}'.format( self.redmine.url, formatter.format(self.resource_class.query_create, **fields)) except KeyError as exception: raise ValidationError('{0} field is required'.format(exception)) self.container = self.resource_class.container_one data = { self.resource_class.container_create: self.prepare_params(formatter.unused_kwargs) } # Almost all resources are created via POST method, but some # resources are created via PUT, so we should check for this try: response = self.redmine.request('post', url, data=data) except ResourceNotFoundError: response = self.redmine.request('put', url, data=data) try: resource = self.to_resource(response[self.container]) except TypeError: raise ValidationError( 'Resource already exists') # fix for repeated PUT requests self.params = formatter.used_kwargs self.url = '{0}{1}'.format( self.redmine.url, self.resource_class.query_one.format(resource.internal_id, **fields)) return resource
def add(self, project_id): """Adds project to contact's project list""" url = '{0}/contacts/{1}/projects.json'.format( self._redmine.url, self._contact_id) try: return self._redmine.request( 'post', url, data={'project': { 'id': project_id }}) except ResourceNotFoundError: raise ValidationError( "Attempt to add contact to a project that doesn't exist") except ForbiddenError: raise ValidationError( 'Attempt to add contact to a project that either has contacts module disabled or is read-only' )
def request(self, method, url, headers=None, params=None, data=None, raw_response=False): """Makes requests to Redmine and returns result in json format""" kwargs = dict( self.requests, **{ 'headers': headers or {}, 'params': params or {}, 'data': data or {}, }) if 'Content-Type' not in kwargs['headers'] and method in ('post', 'put'): kwargs['data'] = json.dumps(data) kwargs['headers']['Content-Type'] = 'application/json' if self.impersonate is not None: kwargs['headers']['X-Redmine-Switch-User'] = self.impersonate # We would like to be authenticated by API key by default if 'key' not in kwargs['params'] and self.key is not None: kwargs['params']['key'] = self.key else: kwargs['auth'] = (self.username, self.password) response = getattr(requests, method)(url, **kwargs) if response.status_code in (200, 201): if raw_response: return response elif not response.content.strip(): return True else: return json_response(response.json) elif response.status_code == 401: raise AuthError elif response.status_code == 404: raise ResourceNotFoundError elif response.status_code == 409: raise ConflictError elif response.status_code == 412 and self.impersonate is not None: raise ImpersonateError elif response.status_code == 413: raise RequestEntityTooLargeError elif response.status_code == 422: errors = json_response(response.json)['errors'] raise ValidationError( to_string(', '.join(e if is_string(e) else ': '.join(e) for e in errors))) elif response.status_code == 500: raise ServerError raise UnknownError(response.status_code)
def delete(self, resource_id, **params): """Deletes a Resource object by resource id (can be either integer id or string identifier)""" if self.resource_class.query_delete is None: raise ResourceBadMethodError() try: url = '{0}{1}'.format( self.redmine.url, self.resource_class.query_delete.format(resource_id, **params)) except KeyError as exception: raise ValidationError('{0} argument is required'.format(exception)) return self.redmine.request('delete', url, params=self.prepare_params(params))
def get(self, resource_id, **params): """Returns a Resource object directly by resource id (can be either integer id or string identifier)""" if self.resource_class.query_one is None or self.resource_class.container_one is None: raise ResourceBadMethodError() try: self.url = '{0}{1}'.format( self.redmine.url, self.resource_class.query_one.format(resource_id, **params)) except KeyError as exception: raise ValidationError('{0} argument is required'.format(exception)) self.params = self.prepare_params(params) self.container = self.resource_class.container_one return self.resource_class(self, self.retrieve()[0])