Skip to content
This repository was archived by the owner on Oct 8, 2024. It is now read-only.

Commit 8ca4b54

Browse files
authored
Merge pull request #1 from correlation-one/shadinaif/add-gcs-backend
feat: add GCS backend
2 parents 6072196 + d91364f commit 8ca4b54

File tree

11 files changed

+209
-102
lines changed

11 files changed

+209
-102
lines changed

.github/workflows/add-depr-ticket-to-depr-board.yml

-19
This file was deleted.

.github/workflows/ci.yml

+2-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Python CI
22

33
on:
44
push:
5-
branches: [master]
5+
branches: [main]
66
pull_request:
77
branches:
88
- '**'
@@ -15,7 +15,7 @@ jobs:
1515
matrix:
1616
os: [ubuntu-20.04]
1717
python-version: ['3.8']
18-
toxenv: [quality, js, django32]
18+
toxenv: [quality, django32]
1919

2020
steps:
2121
- uses: actions/checkout@v2
@@ -40,10 +40,3 @@ jobs:
4040
env:
4141
TOXENV: ${{ matrix.toxenv }}
4242
run: tox
43-
44-
- name: Run Coverage
45-
if: matrix.python-version == '3.8' && matrix.toxenv=='django32'
46-
uses: codecov/codecov-action@v1
47-
with:
48-
flags: unittests
49-
fail_ci_if_error: true

.github/workflows/commitlint.yml

-10
This file was deleted.

.github/workflows/pypi-publish.yml

-31
This file was deleted.

.github/workflows/upgrade-python-requirements.yml

-27
This file was deleted.

openassessment/fileupload/backends/__init__.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from django.conf import settings
55

6-
from . import django_storage, filesystem, s3, swift
6+
from . import django_storage, gcs, filesystem, s3, swift
77

88

99
def get_backend():
@@ -20,5 +20,7 @@ def get_backend():
2020
return swift.Backend()
2121
elif backend_setting == "django":
2222
return django_storage.Backend()
23+
elif backend_setting == "gcs":
24+
return gcs.GCSBackend()
2325
else:
2426
raise ValueError("Invalid ORA2_FILEUPLOAD_BACKEND setting value: %s" % backend_setting)
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""GCS Bucket File Upload Backend."""
2+
3+
import functools
4+
import logging
5+
from google.cloud import storage
6+
7+
from ..exceptions import FileUploadInternalError
8+
from .base import BaseBackend
9+
10+
log = logging.getLogger("openassessment.fileupload.api") # pylint: disable=invalid-name
11+
12+
13+
def catch_broad_exception(method):
14+
"""Decorator to catch broad exceptions, log them, and raise a FileUploadInternalError."""
15+
@functools.wraps(method)
16+
def wrapper(*args, **kwargs):
17+
try:
18+
return method(*args, **kwargs)
19+
except Exception as ex: # pylint: disable=broad-except
20+
log.exception(
21+
f"Internal exception occurred while executing ora2 file-upload backend gcs.{method.__name__}: {str(ex)}"
22+
)
23+
raise FileUploadInternalError(ex) from ex
24+
return wrapper
25+
26+
27+
class GCSBackend(BaseBackend):
28+
""" GCS Bucket File Upload Backend. """
29+
30+
@catch_broad_exception
31+
def get_upload_url(self, key, content_type):
32+
"""Get a signed URL for uploading a file to GCS"""
33+
bucket_name, key_name = self._retrieve_parameters(key)
34+
blob = get_blob_object(bucket_name, key_name)
35+
return blob.generate_signed_url(
36+
version="v4",
37+
expiration=self.UPLOAD_URL_TIMEOUT,
38+
method="PUT",
39+
content_type=content_type,
40+
)
41+
42+
@catch_broad_exception
43+
def get_download_url(self, key):
44+
"""Get a signed URL for downloading a file from GCS"""
45+
bucket_name, key_name = self._retrieve_parameters(key)
46+
blob = get_blob_object(bucket_name, key_name)
47+
if not blob.exists():
48+
return ""
49+
return blob.generate_signed_url(
50+
version="v4",
51+
expiration=self.DOWNLOAD_URL_TIMEOUT,
52+
method="GET",
53+
)
54+
55+
@catch_broad_exception
56+
def remove_file(self, key):
57+
"""Remove a file from GCS"""
58+
bucket_name, key_name = self._retrieve_parameters(key)
59+
blob = get_blob_object(bucket_name, key_name)
60+
if blob.exists():
61+
blob.delete()
62+
return True
63+
return False
64+
65+
66+
def get_blob_object(bucket_name, key_name):
67+
"""Get a blob object from GCS"""
68+
client = storage.Client()
69+
return client.bucket(bucket_name).blob(key_name)

requirements/quality.txt

+48-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# This file is autogenerated by pip-compile with python 3.8
33
# To update, run:
44
#
5-
# make upgrade
5+
# pip-compile --output-file=requirements/quality.txt requirements/quality.in
66
#
77
appdirs==1.4.4
88
# via
@@ -54,6 +54,10 @@ botocore==1.27.66
5454
# boto3
5555
# moto
5656
# s3transfer
57+
cachetools==5.3.2
58+
# via
59+
# -r requirements/test.txt
60+
# google-auth
5761
certifi==2022.6.15
5862
# via
5963
# -r requirements/test.txt
@@ -196,6 +200,36 @@ fs-s3fs==0.1.8
196200
# -c requirements/constraints.txt
197201
# -r requirements/test.txt
198202
# django-pyfs
203+
google-api-core==2.17.0
204+
# via
205+
# -r requirements/test.txt
206+
# google-cloud-core
207+
# google-cloud-storage
208+
google-auth==2.27.0
209+
# via
210+
# -r requirements/test.txt
211+
# google-api-core
212+
# google-cloud-core
213+
# google-cloud-storage
214+
google-cloud-core==2.4.1
215+
# via
216+
# -r requirements/test.txt
217+
# google-cloud-storage
218+
google-cloud-storage==2.14.0
219+
# via -r requirements/test.txt
220+
google-crc32c==1.5.0
221+
# via
222+
# -r requirements/test.txt
223+
# google-cloud-storage
224+
# google-resumable-media
225+
google-resumable-media==2.7.0
226+
# via
227+
# -r requirements/test.txt
228+
# google-cloud-storage
229+
googleapis-common-protos==1.62.0
230+
# via
231+
# -r requirements/test.txt
232+
# google-api-core
199233
html5lib==1.1
200234
# via -r requirements/test.txt
201235
idna==2.8
@@ -326,6 +360,11 @@ polib==1.1.1
326360
# via
327361
# -r requirements/test.txt
328362
# edx-i18n-tools
363+
protobuf==4.25.2
364+
# via
365+
# -r requirements/test.txt
366+
# google-api-core
367+
# googleapis-common-protos
329368
psutil==5.9.1
330369
# via
331370
# -r requirements/test.txt
@@ -338,8 +377,13 @@ py==1.11.0
338377
pyasn1==0.4.8
339378
# via
340379
# -r requirements/test.txt
380+
# pyasn1-modules
341381
# python-jose
342382
# rsa
383+
pyasn1-modules==0.3.0
384+
# via
385+
# -r requirements/test.txt
386+
# google-auth
343387
pycodestyle==2.9.1
344388
# via -r requirements/quality.in
345389
pycparser==2.21
@@ -431,6 +475,8 @@ requests==2.28.1
431475
# via
432476
# -r requirements/test.txt
433477
# docker
478+
# google-api-core
479+
# google-cloud-storage
434480
# moto
435481
# python-swiftclient
436482
# responses
@@ -441,6 +487,7 @@ responses==0.21.0
441487
rsa==4.9
442488
# via
443489
# -r requirements/test.txt
490+
# google-auth
444491
# python-jose
445492
s3transfer==0.6.0
446493
# via

0 commit comments

Comments
 (0)