Skip to content
1 change: 1 addition & 0 deletions syncano/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
from .push_notification import * # NOQA
from .geo import * # NOQA
from .backups import * # NOQA
from .hosting import * # NOQA
from .data_views import DataEndpoint as EndpointData # NOQA
10 changes: 10 additions & 0 deletions syncano/models/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,16 @@ def to_native(self, value):
return value


class ListField(WritableField):

def validate(self, value, model_instance):
if value is None:
return

if not isinstance(value, list):
raise self.ValidationError('List expected.')


class GeoPointField(Field):

field_lookups = ['near', 'exists']
Expand Down
59 changes: 59 additions & 0 deletions syncano/models/hosting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
from . import fields
from .base import Instance, Model, logger


class Hosting(Model):
"""
OO wrapper around hosting.
"""

label = fields.StringField(max_length=64, primary_key=True)
description = fields.StringField(read_only=False, required=False)
domains = fields.ListField(default=[])

id = fields.IntegerField(read_only=True)
links = fields.LinksField()
created_at = fields.DateTimeField(read_only=True, required=False)
updated_at = fields.DateTimeField(read_only=True, required=False)

class Meta:
parent = Instance
endpoints = {
'detail': {
'methods': ['delete', 'get', 'put', 'patch'],
'path': '/hosting/{id}/',
},
'list': {
'methods': ['post', 'get'],
'path': '/hosting/',
}
}

def upload_file(self, path, file):
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,
data=data, files=[('file', file)])
if response.status_code != 201:
logger.error(response.text)
return
return response

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']]

def set_default(self):
default_path = self.links.set_default
connection = self._get_connection()

response = connection.make_request('POST', default_path)
self.to_python(response)
return self
1 change: 1 addition & 0 deletions syncano/models/instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class Instance(RenameMixin, Model):
schedules = fields.RelatedManagerField('Schedule')
classes = fields.RelatedManagerField('Class')
invitations = fields.RelatedManagerField('InstanceInvitation')
hostings = fields.RelatedManagerField('Hosting')

# push notifications fields;
gcm_devices = fields.RelatedManagerField('GCMDevice')
Expand Down
36 changes: 36 additions & 0 deletions tests/integration_tests_hosting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
import uuid

from tests.integration_test import InstanceMixin, IntegrationTest

try:
# python2
from StringIO import StringIO
except ImportError:
# python3
from io import StringIO


class HostingIntegrationTests(InstanceMixin, IntegrationTest):

def setUp(self):
self.hosting = self.instance.hostings.create(
label='test12',
description='desc',
domains=['test.test{}.io'.format(uuid.uuid4().hex[:5])]
)

def test_create_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)

files_list = self.hosting.list_files()

self.assertIn('styles/main.css', files_list)

def test_set_default(self):
hosting = self.hosting.set_default()
self.assertIn('default', hosting.domains)