diff --git a/syncano/__init__.py b/syncano/__init__.py index e0c54af..311afea 100644 --- a/syncano/__init__.py +++ b/syncano/__init__.py @@ -2,7 +2,7 @@ import os __title__ = 'Syncano Python' -__version__ = '5.4.0' +__version__ = '5.4.1' __author__ = "Daniel Kopka, Michal Kobus, and Sebastian Opalczynski" __credits__ = ["Daniel Kopka", "Michal Kobus", diff --git a/syncano/models/hosting.py b/syncano/models/hosting.py index 39c32e7..ab80819 100644 --- a/syncano/models/hosting.py +++ b/syncano/models/hosting.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- + from . import fields from .base import Instance, Model, logger @@ -31,24 +32,54 @@ class Meta: } def upload_file(self, path, file): + """ + Upload a new file to the hosting. + :param path: the file path; + :param file: the file to be uploaded; + :return: the response from the API; + """ files_path = self.links.files data = {'path': path} connection = self._get_connection() - params = connection.build_params(params={}) - headers = params['headers'] - headers.pop('content-type') - response = connection.session.post(connection.host + files_path, headers=headers, + headers = self._prepare_header(connection) + response = connection.session.post('{}{}'.format(connection.host, files_path), headers=headers, data=data, files=[('file', file)]) if response.status_code != 201: logger.error(response.text) return - return response + return HostingFile(**response.json()) + + def update_file(self, path, file): + """ + Updates an existing file. + :param path: the file path; + :param file: the file to be uploaded; + :return: the response from the API; + """ + hosting_files = self._get_files() + is_found = False + + for hosting_file in hosting_files: + if hosting_file.path == path: + is_found = True + break + + if not is_found: + # create if not found; + hosting_file = self.upload_file(path, file) + return hosting_file - def list_files(self): - files_path = self.links.files connection = self._get_connection() - response = connection.request('GET', files_path) - return [f['path'] for f in response['objects']] + headers = self._prepare_header(connection) + response = connection.session.patch('{}{}'.format(connection.host, hosting_file.links.self), headers=headers, + files=[('file', file)]) + if response.status_code != 200: + logger.error(response.text) + return + return HostingFile(**response.json()) + + def list_files(self): + return self._get_files() def set_default(self): default_path = self.links.set_default @@ -57,3 +88,35 @@ def set_default(self): response = connection.make_request('POST', default_path) self.to_python(response) return self + + def _prepare_header(self, connection): + params = connection.build_params(params={}) + headers = params['headers'] + headers.pop('content-type') + return headers + + def _get_files(self): + return [hfile for hfile in HostingFile.please.list(hosting_id=self.id)] + + +class HostingFile(Model): + """ + OO wrapper around hosting file. + """ + + path = fields.StringField(max_length=300) + file = fields.FileField() + links = fields.LinksField() + + class Meta: + parent = Hosting + endpoints = { + 'detail': { + 'methods': ['delete', 'get', 'put', 'patch'], + 'path': '/files/{id}/', + }, + 'list': { + 'methods': ['post', 'get'], + 'path': '/files/', + } + } diff --git a/syncano/models/manager.py b/syncano/models/manager.py index 07d6d5c..c6ab313 100644 --- a/syncano/models/manager.py +++ b/syncano/models/manager.py @@ -972,9 +972,16 @@ def _build_query(self, query_data, **kwargs): if self.LOOKUP_SEPARATOR in field_name: model_name, field_name, lookup = self._get_lookup_attributes(field_name) - for field in model._meta.fields: - if field.name == field_name: - break + # if filter is made on relation field: relation__name__eq='test'; + if model_name: + for field in model._meta.fields: + if field.name == model_name: + break + # if filter is made on normal field: name__eq='test'; + else: + for field in model._meta.fields: + if field.name == field_name: + break self._validate_lookup(model, model_name, field_name, lookup, field) diff --git a/tests/integration_test_relations.py b/tests/integration_test_relations.py index 37348b6..052a424 100644 --- a/tests/integration_test_relations.py +++ b/tests/integration_test_relations.py @@ -3,11 +3,11 @@ from tests.integration_test import InstanceMixin, IntegrationTest -class ResponseTemplateApiTest(InstanceMixin, IntegrationTest): +class RelationApiTest(InstanceMixin, IntegrationTest): @classmethod def setUpClass(cls): - super(ResponseTemplateApiTest, cls).setUpClass() + super(RelationApiTest, cls).setUpClass() # prapare data cls.author = Class.please.create(name="author", schema=[ @@ -90,3 +90,10 @@ def test_related_field_lookup_is(self): self.assertEqual(len(list(filtered_books)), 1) for book in filtered_books: self.assertEqual(book.title, self.niezwyciezony.title) + + def test_multiple_lookups(self): + filtered_books = self.book.objects.list().filter(authors__id__in=[self.prus.id], title__eq='Lalka') + + self.assertEqual(len(list(filtered_books)), 1) + for book in filtered_books: + self.assertEqual(book.title, self.lalka.title) diff --git a/tests/integration_tests_hosting.py b/tests/integration_tests_hosting.py index 8056ae1..1be56a5 100644 --- a/tests/integration_tests_hosting.py +++ b/tests/integration_tests_hosting.py @@ -25,12 +25,23 @@ def test_create_file(self): a_hosting_file.write('h1 {color: #541231;}') a_hosting_file.seek(0) - self.hosting.upload_file(path='styles/main.css', file=a_hosting_file) - - files_list = self.hosting.list_files() - - self.assertIn('styles/main.css', files_list) + hosting_file = self.hosting.upload_file(path='styles/main.css', file=a_hosting_file) + self.assertEqual(hosting_file.path, 'styles/main.css') def test_set_default(self): hosting = self.hosting.set_default() self.assertIn('default', hosting.domains) + + def test_update_file(self): + a_hosting_file = StringIO() + a_hosting_file.write('h1 {color: #541231;}') + a_hosting_file.seek(0) + + self.hosting.upload_file(path='styles/main.css', file=a_hosting_file) + + a_hosting_file = StringIO() + a_hosting_file.write('h2 {color: #541231;}') + a_hosting_file.seek(0) + + hosting_file = self.hosting.update_file(path='styles/main.css', file=a_hosting_file) + self.assertEqual(hosting_file.path, 'styles/main.css')