Skip to content

Commit 92220ba

Browse files
committed
wip
1 parent 6790e61 commit 92220ba

File tree

11 files changed

+335
-88
lines changed

11 files changed

+335
-88
lines changed

conftest.py

+90-3
Original file line numberDiff line numberDiff line change
@@ -580,16 +580,22 @@ def svc_client(mock_redis):
580580
def svc_client_with_repo(svc_client, mock_redis):
581581
"""Renku service remote repository."""
582582
remote_url = 'https://renkulab.io/gitlab/contact/integration-tests.git'
583-
headers = {'Authorization': 'Bearer b4b4de0eda0f471ab82702bd5c367fa7'}
583+
headers = {
584+
'Content-Type': 'application/json',
585+
'accept': 'application/json',
586+
'Authorization': 'Bearer b4b4de0eda0f471ab82702bd5c367fa7',
587+
}
584588

585-
params = {
589+
payload = {
586590
'git_url': remote_url,
587591
'git_username': 'contact',
588592
'git_access_token': 'EcfPJvEqjJepyu6XyqKZ',
589593
}
590594

591595
response = svc_client.post(
592-
'/cache/project-clone', data=params, headers=headers
596+
'/cache/project-clone',
597+
data=json.dumps(payload),
598+
headers=headers,
593599
)
594600

595601
assert response
@@ -599,3 +605,84 @@ def svc_client_with_repo(svc_client, mock_redis):
599605
assert isinstance(uuid.UUID(project_id), uuid.UUID)
600606

601607
yield svc_client, headers, project_id
608+
609+
610+
@pytest.fixture(
611+
params=[
612+
{
613+
'url': '/cache/files-list',
614+
'allowed_method': 'GET',
615+
'headers': {
616+
'Content-Type': 'application/json',
617+
'accept': 'application/json',
618+
}
619+
},
620+
{
621+
'url': '/cache/files-upload',
622+
'allowed_method': 'POST',
623+
'headers': {}
624+
},
625+
{
626+
'url': '/cache/project-clone',
627+
'allowed_method': 'POST',
628+
'headers': {
629+
'Content-Type': 'application/json',
630+
'accept': 'application/json',
631+
}
632+
},
633+
{
634+
'url': '/cache/project-list',
635+
'allowed_method': 'GET',
636+
'headers': {
637+
'Content-Type': 'application/json',
638+
'accept': 'application/json',
639+
}
640+
},
641+
{
642+
'url': '/datasets/add',
643+
'allowed_method': 'POST',
644+
'headers': {
645+
'Content-Type': 'application/json',
646+
'accept': 'application/json',
647+
}
648+
},
649+
{
650+
'url': '/datasets/create',
651+
'allowed_method': 'POST',
652+
'headers': {
653+
'Content-Type': 'application/json',
654+
'accept': 'application/json',
655+
}
656+
},
657+
{
658+
'url': '/datasets/files-list',
659+
'allowed_method': 'GET',
660+
'headers': {
661+
'Content-Type': 'application/json',
662+
'accept': 'application/json',
663+
}
664+
},
665+
{
666+
'url': '/datasets/list',
667+
'allowed_method': 'GET',
668+
'headers': {
669+
'Content-Type': 'application/json',
670+
'accept': 'application/json',
671+
}
672+
},
673+
]
674+
)
675+
def service_allowed_endpoint(request, svc_client, mock_redis):
676+
"""Ensure allowed methods and correct headers."""
677+
methods = {
678+
'GET': svc_client.get,
679+
'POST': svc_client.post,
680+
'HEAD': svc_client.head,
681+
'PUT': svc_client.put,
682+
'DELETE': svc_client.delete,
683+
'OPTIONS': svc_client.options,
684+
'TRACE': svc_client.trace,
685+
'PATCH': svc_client.patch,
686+
}
687+
688+
yield methods, request.param, svc_client

renku/cli/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
option_use_external_storage
9191
from renku.core.commands.version import check_version, print_version
9292
from renku.core.management.client import LocalClient
93-
from renku.core.management.config import ConfigManagerMixin, RENKU_HOME
93+
from renku.core.management.config import RENKU_HOME, ConfigManagerMixin
9494
from renku.core.management.repository import default_path
9595

9696
#: Monkeypatch Click application.

renku/service/config.py

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
RENKU_EXCEPTION_ERROR_CODE = -32100
2727
REDIS_EXCEPTION_ERROR_CODE = -32200
2828

29+
INVALID_HEADERS_ERROR_CODE = -32601
2930
INVALID_PARAMS_ERROR_CODE = -32602
3031
INTERNAL_FAILURE_ERROR_CODE = -32603
3132

renku/service/serializers/cache.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,18 @@ class FileListResponseRPC(JsonRPCResponse):
9595
class ProjectCloneRequest(Schema):
9696
"""Request schema for project clone."""
9797

98-
project_id = fields.String(missing=lambda: uuid.uuid4().hex)
99-
name = fields.String(required=True)
100-
owner = fields.String(required=True)
101-
10298
git_url = fields.String(required=True)
10399
git_username = fields.String(required=True)
104100
git_access_token = fields.String(required=True)
105101

102+
103+
class ProjectCloneDetails(ProjectCloneRequest):
104+
"""Details schema for project clone."""
105+
106+
project_id = fields.String(missing=lambda: uuid.uuid4().hex)
107+
name = fields.String(required=True)
108+
owner = fields.String(required=True)
109+
106110
@validates('git_url')
107111
def validate_git_url(self, value):
108112
"""Validates git url."""

renku/service/utils/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
# limitations under the License.
1818
"""Renku service utility functions."""
1919
from git import Repo
20+
2021
from renku.service.config import CACHE_PROJECTS_PATH, CACHE_UPLOADS_PATH
2122

2223

renku/service/views/cache.py

+10-7
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
INVALID_PARAMS_ERROR_CODE, SUPPORTED_ARCHIVES
3232
from renku.service.serializers.cache import FileListResponse, \
3333
FileListResponseRPC, FileUploadDetails, FileUploadRequest, \
34-
FileUploadResponse, FileUploadResponseRPC, ProjectCloneRequest, \
35-
ProjectCloneResponse, ProjectCloneResponseRPC, ProjectListResponse, \
36-
ProjectListResponseRPC, extract_file
34+
FileUploadResponse, FileUploadResponseRPC, ProjectCloneDetails, \
35+
ProjectCloneRequest, ProjectCloneResponse, ProjectCloneResponseRPC, \
36+
ProjectListResponse, ProjectListResponseRPC, extract_file
3737
from renku.service.utils import make_file_path, make_project_path
38-
from renku.service.views.decorators import handle_base_except, \
38+
from renku.service.views.decorators import accepts_json, handle_base_except, \
3939
handle_git_except, handle_renku_except, handle_validation_except, \
4040
header_doc, requires_cache, requires_identity
4141

@@ -156,7 +156,10 @@ def upload_file_view(user, cache):
156156

157157
@use_kwargs(ProjectCloneRequest)
158158
@marshal_with(ProjectCloneResponseRPC)
159-
@header_doc('Clone a remote project.', tags=(CACHE_BLUEPRINT_TAG, ))
159+
@header_doc(
160+
'Clone a remote project. If the project is cached already, '
161+
'new clone operation will override the old cache state.',
162+
tags=(CACHE_BLUEPRINT_TAG, ))
160163
@cache_blueprint.route(
161164
'/cache/project-clone',
162165
methods=['POST'],
@@ -168,10 +171,10 @@ def upload_file_view(user, cache):
168171
@handle_validation_except
169172
@requires_cache
170173
@requires_identity
174+
@accepts_json
171175
def project_clone(user, cache):
172176
"""Clone a remote repository."""
173-
ctx = ProjectCloneRequest().load(dict(request.form))
174-
177+
ctx = ProjectCloneDetails().load(request.json)
175178
local_path = make_project_path(user, ctx)
176179
if local_path.exists():
177180
shutil.rmtree(local_path)

renku/service/views/datasets.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
DatasetFilesListResponseRPC, DatasetListRequest, DatasetListResponse, \
3535
DatasetListResponseRPC
3636
from renku.service.utils import make_file_path, make_project_path, repo_sync
37-
from renku.service.views.decorators import handle_base_except, \
37+
from renku.service.views.decorators import accepts_json, handle_base_except, \
3838
handle_git_except, handle_renku_except, handle_validation_except, \
3939
header_doc, requires_cache, requires_identity
4040

@@ -137,11 +137,12 @@ def list_dataset_files_view(user, cache):
137137
@handle_git_except
138138
@handle_renku_except
139139
@handle_validation_except
140+
@accepts_json
140141
@requires_cache
141142
@requires_identity
142143
def add_file_to_dataset_view(user, cache):
143144
"""Add uploaded file to cloned repository."""
144-
ctx = DatasetAddRequest().load(request.form)
145+
ctx = DatasetAddRequest().load(request.json)
145146
project = cache.get_project(user, ctx['project_id'])
146147
file = cache.get_file(user, ctx['file_id'])
147148

@@ -196,11 +197,12 @@ def add_file_to_dataset_view(user, cache):
196197
@handle_git_except
197198
@handle_renku_except
198199
@handle_validation_except
200+
@accepts_json
199201
@requires_cache
200202
@requires_identity
201203
def create_dataset_view(user, cache):
202204
"""Create a new dataset in a project."""
203-
ctx = DatasetCreateRequest().load(request.form)
205+
ctx = DatasetCreateRequest().load(request.json)
204206
project = cache.get_project(user, ctx['project_id'])
205207

206208
project_path = make_project_path(user, project)

renku/service/views/decorators.py

+30-3
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
from renku.core.errors import RenkuException
2929
from renku.service.config import GIT_ACCESS_DENIED_ERROR_CODE, \
3030
GIT_UNKNOWN_ERROR_CODE, INTERNAL_FAILURE_ERROR_CODE, \
31-
INVALID_PARAMS_ERROR_CODE, REDIS_EXCEPTION_ERROR_CODE, \
32-
RENKU_EXCEPTION_ERROR_CODE
31+
INVALID_HEADERS_ERROR_CODE, INVALID_PARAMS_ERROR_CODE, \
32+
REDIS_EXCEPTION_ERROR_CODE, RENKU_EXCEPTION_ERROR_CODE
3333

3434

3535
def requires_identity(f):
@@ -42,7 +42,7 @@ def decorated_function(*args, **kws):
4242
if user and not user[0]:
4343
return jsonify(
4444
error={
45-
'code': INVALID_PARAMS_ERROR_CODE,
45+
'code': INVALID_HEADERS_ERROR_CODE,
4646
'reason': 'user identification is missing'
4747
}
4848
)
@@ -146,6 +146,33 @@ def decorated_function(*args, **kwargs):
146146
return decorated_function
147147

148148

149+
def accepts_json(f):
150+
"""Wrapper which ensures only JSON payload can be in request."""
151+
# nowa
152+
@wraps(f)
153+
def decorated_function(*args, **kwargs):
154+
"""Represents decorated function."""
155+
if 'Content-Type' not in request.headers:
156+
return jsonify(
157+
error={
158+
'code': INVALID_HEADERS_ERROR_CODE,
159+
'reason': 'invalid request headers'
160+
}
161+
)
162+
163+
header_check = request.headers['Content-Type'] == 'application/json'
164+
165+
if not request.is_json or not header_check:
166+
return jsonify(error={
167+
'code': INVALID_HEADERS_ERROR_CODE,
168+
'reason': 'invalid request payload'
169+
})
170+
171+
return f(*args, **kwargs)
172+
173+
return decorated_function
174+
175+
149176
def handle_base_except(f):
150177
"""Wrapper which handles base exceptions."""
151178
# nowa

0 commit comments

Comments
 (0)