Skip to content
2 changes: 1 addition & 1 deletion syncano/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
81 changes: 72 additions & 9 deletions syncano/models/hosting.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-

from . import fields
from .base import Instance, Model, logger

Expand Down Expand Up @@ -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
Expand All @@ -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/',
}
}
13 changes: 10 additions & 3 deletions syncano/models/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
11 changes: 9 additions & 2 deletions tests/integration_test_relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -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=[
Expand Down Expand Up @@ -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)
21 changes: 16 additions & 5 deletions tests/integration_tests_hosting.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')