Skip to content

Commit 9870fc6

Browse files
authored
Merge pull request #223 from Syncano/LIB-816
[LIB-816] Provide hosting support to LIB
2 parents 0546557 + bf5d8c1 commit 9870fc6

File tree

5 files changed

+107
-0
lines changed

5 files changed

+107
-0
lines changed

syncano/models/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@
1111
from .push_notification import * # NOQA
1212
from .geo import * # NOQA
1313
from .backups import * # NOQA
14+
from .hosting import * # NOQA
1415
from .data_views import DataEndpoint as EndpointData # NOQA

syncano/models/fields.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,16 @@ def to_native(self, value):
716716
return value
717717

718718

719+
class ListField(WritableField):
720+
721+
def validate(self, value, model_instance):
722+
if value is None:
723+
return
724+
725+
if not isinstance(value, list):
726+
raise self.ValidationError('List expected.')
727+
728+
719729
class GeoPointField(Field):
720730

721731
field_lookups = ['near', 'exists']

syncano/models/hosting.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# -*- coding: utf-8 -*-
2+
from . import fields
3+
from .base import Instance, Model, logger
4+
5+
6+
class Hosting(Model):
7+
"""
8+
OO wrapper around hosting.
9+
"""
10+
11+
label = fields.StringField(max_length=64, primary_key=True)
12+
description = fields.StringField(read_only=False, required=False)
13+
domains = fields.ListField(default=[])
14+
15+
id = fields.IntegerField(read_only=True)
16+
links = fields.LinksField()
17+
created_at = fields.DateTimeField(read_only=True, required=False)
18+
updated_at = fields.DateTimeField(read_only=True, required=False)
19+
20+
class Meta:
21+
parent = Instance
22+
endpoints = {
23+
'detail': {
24+
'methods': ['delete', 'get', 'put', 'patch'],
25+
'path': '/hosting/{id}/',
26+
},
27+
'list': {
28+
'methods': ['post', 'get'],
29+
'path': '/hosting/',
30+
}
31+
}
32+
33+
def upload_file(self, path, file):
34+
files_path = self.links.files
35+
data = {'path': path}
36+
connection = self._get_connection()
37+
params = connection.build_params(params={})
38+
headers = params['headers']
39+
headers.pop('content-type')
40+
response = connection.session.post(connection.host + files_path, headers=headers,
41+
data=data, files=[('file', file)])
42+
if response.status_code != 201:
43+
logger.error(response.text)
44+
return
45+
return response
46+
47+
def list_files(self):
48+
files_path = self.links.files
49+
connection = self._get_connection()
50+
response = connection.request('GET', files_path)
51+
return [f['path'] for f in response['objects']]
52+
53+
def set_default(self):
54+
default_path = self.links.set_default
55+
connection = self._get_connection()
56+
57+
response = connection.make_request('POST', default_path)
58+
self.to_python(response)
59+
return self

syncano/models/instances.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class Instance(RenameMixin, Model):
6161
schedules = fields.RelatedManagerField('Schedule')
6262
classes = fields.RelatedManagerField('Class')
6363
invitations = fields.RelatedManagerField('InstanceInvitation')
64+
hostings = fields.RelatedManagerField('Hosting')
6465

6566
# push notifications fields;
6667
gcm_devices = fields.RelatedManagerField('GCMDevice')

tests/integration_tests_hosting.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# -*- coding: utf-8 -*-
2+
import uuid
3+
4+
from tests.integration_test import InstanceMixin, IntegrationTest
5+
6+
try:
7+
# python2
8+
from StringIO import StringIO
9+
except ImportError:
10+
# python3
11+
from io import StringIO
12+
13+
14+
class HostingIntegrationTests(InstanceMixin, IntegrationTest):
15+
16+
def setUp(self):
17+
self.hosting = self.instance.hostings.create(
18+
label='test12',
19+
description='desc',
20+
domains=['test.test{}.io'.format(uuid.uuid4().hex[:5])]
21+
)
22+
23+
def test_create_file(self):
24+
a_hosting_file = StringIO()
25+
a_hosting_file.write('h1 {color: #541231;}')
26+
a_hosting_file.seek(0)
27+
28+
self.hosting.upload_file(path='styles/main.css', file=a_hosting_file)
29+
30+
files_list = self.hosting.list_files()
31+
32+
self.assertIn('styles/main.css', files_list)
33+
34+
def test_set_default(self):
35+
hosting = self.hosting.set_default()
36+
self.assertIn('default', hosting.domains)

0 commit comments

Comments
 (0)