diff --git a/.dockerignore b/.dockerignore index a71e59b..414f92e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -26,4 +26,4 @@ *.pyo *.pyd README.md -.admin/tokens \ No newline at end of file +.admin/tokens diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..cf7f88b --- /dev/null +++ b/.flake8 @@ -0,0 +1,5 @@ +[flake8] +ignore = D203 +exclude = .git,__pycache__,docs/source/conf.py,old,build,dist +max-complexity = 10 +max-line-length = 88 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5232ca9 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,18 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.3.0 + hooks: + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + +- repo: https://github.com/psf/black + rev: 19.3b0 + hooks: + - id: black + args: ['--skip-string-normalization'] + +- repo: https://github.com/pycqa/flake8 + rev: 3.9.2 + hooks: + - id: flake8 diff --git a/.vscode/launch.json b/.vscode/launch.json index ba8240e..cc5c21d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -114,4 +114,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index e7ec5c0..43c6bc3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,7 +24,7 @@ "python.linting.pylintEnabled": true, "[python]": { "editor.insertSpaces": true, - "editor.tabSize": 4 + "editor.tabSize": 4 }, "todo-tree.highlights.customHighlight": { "TODO": { diff --git a/LICENSE b/LICENSE index d71edfa..f186302 100644 --- a/LICENSE +++ b/LICENSE @@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/cannlytics_api/api/auth.py b/cannlytics_api/api/auth.py index e8edd51..46c1a22 100644 --- a/cannlytics_api/api/auth.py +++ b/cannlytics_api/api/auth.py @@ -1,11 +1,11 @@ - from firebase_admin import auth + def authenticate(request): - """ Identify the user's Firebase account using an ID token. """ - authorization = request.headers["Authorization"] + """Identify the user's Firebase account using an ID token.""" + authorization = request.headers['Authorization'] token = authorization.split(' ')[1] claims = auth.verify_id_token(token) uid = claims['uid'] - request.session['uid'] = uid # Save user's custom claims in a session? - return claims \ No newline at end of file + request.session['uid'] = uid # Save user's custom claims in a session? + return claims diff --git a/cannlytics_api/api/base.py b/cannlytics_api/api/base.py index 7e45c50..1526c60 100644 --- a/cannlytics_api/api/base.py +++ b/cannlytics_api/api/base.py @@ -1,22 +1,24 @@ from rest_framework.decorators import api_view from rest_framework.response import Response -BASE = "https://api.cannlytics.com" -ENDPOINTS = ["labs"] -VERSION = "v1" +BASE = 'https://api.cannlytics.com' +ENDPOINTS = ['labs'] +VERSION = 'v1' @api_view(['GET']) def index(request, format=None): """Informational base endpoint.""" - message = f"Welcome to the Cannlytics API. The current version is {VERSION} and is located at {BASE}/{VERSION}." - return Response({ "data": message}, content_type="application/json") + message = 'Welcome to the Cannlytics API.' + message += f'The current version is {VERSION} and is located at {BASE}/{VERSION}.' + return Response({'data': message}, content_type='application/json') @api_view(['GET']) def base(request, format=None): """Informational version endpoint.""" - message = f"Welcome to {VERSION} of the Cannlytics API. Available endpoints:\n\n" + message = f'Welcome to {VERSION} of the Cannlytics API.' + message += 'Available endpoints:\n\n' for endpoint in ENDPOINTS: - message += f"{endpoint}\n" - return Response({ "data": message}, content_type="application/json") + message += f'{endpoint}\n' + return Response({'data': message}, content_type='application/json') diff --git a/cannlytics_api/api/cannlypedia.py b/cannlytics_api/api/cannlypedia.py index 05791b3..b0f1067 100644 --- a/cannlytics_api/api/cannlypedia.py +++ b/cannlytics_api/api/cannlypedia.py @@ -1,6 +1,7 @@ from rest_framework.decorators import api_view from rest_framework.response import Response + @api_view(['GET']) def scholars(request, format=None): """Get information about scholars.""" @@ -9,6 +10,7 @@ def scholars(request, format=None): author = request.query_params.get('q', None) if author: from scholarly import scholarly + search_query = scholarly.search_author(author) author_source = next(search_query) author_data = { @@ -18,9 +20,11 @@ def scholars(request, format=None): 'email_domain': author_source['email_domain'], 'interests': author_source['interests'], 'photo_url': author_source['url_picture'], - } - return Response(author_data, content_type="application/json") - + } + return Response(author_data, content_type='application/json') + # Return an error if no author is specified. - error_message = 'Author not found in request. Specify ?q={url_encoded_author_name}' - return Response({ "error": error_message}, content_type="application/json") + error_message = ( + 'Author not found in request. Specify ?q={url_encoded_author_name}' + ) + return Response({'error': error_message}, content_type='application/json') diff --git a/cannlytics_api/api/labs.py b/cannlytics_api/api/labs.py index 752b618..606667d 100644 --- a/cannlytics_api/api/labs.py +++ b/cannlytics_api/api/labs.py @@ -16,8 +16,8 @@ def lab(request, format=None): limit = request.query_params.get("limit", None) order_by = request.query_params.get("order_by", "state") # TODO: Get any filters from dict(request.query_params) - labs = get_collection('labs', order_by=order_by, limit=limit, filters=[]) - return Response({ "data": labs}, content_type="application/json") + labs = get_collection("labs", order_by=order_by, limit=limit, filters=[]) + return Response({"data": labs}, content_type="application/json") @api_view(['GET', 'POST']) @@ -29,8 +29,8 @@ def labs(request, format=None): limit = request.query_params.get("limit", None) order_by = request.query_params.get("order_by", "state") # TODO: Get any filters from dict(request.query_params) - labs = get_collection('labs', order_by=order_by, limit=limit, filters=[]) - return Response({ "data": labs}, content_type="application/json") + labs = get_collection("labs", order_by=order_by, limit=limit, filters=[]) + return Response({"data": labs}, content_type="application/json") # Update a lab given a valid Firebase token. elif request.method == 'POST': @@ -38,8 +38,10 @@ def labs(request, format=None): # Check token. try: claims = authenticate(request) - except: - return Response({"error": "Could not authenticate."}, status=status.HTTP_400_BAD_REQUEST) + except Exception: # TODO: what is the correct exception? + return Response( + {"error": "Could not authenticate."}, status=status.HTTP_400_BAD_REQUEST + ) # Get the posted lab data. lab = request.data @@ -56,7 +58,7 @@ def labs(request, format=None): before = existing_data[key] if before != after: changes.append({"key": key, "before": before, "after": after}) - + # Get a timestamp. timestamp = datetime.now().isoformat() lab["updated_at"] = timestamp @@ -86,12 +88,11 @@ def lab_logs(request, org_id, format=None): if request.method == 'GET': data = get_collection(f"labs/{org_id}/logs") - return Response({ "data": data}, content_type="application/json") - + return Response({"data": data}, content_type="application/json") + elif request.method == 'POST': # TODO: Create a log. - return Response({ "data": "Under construction"}, content_type="application/json") - + return Response({"data": "Under construction"}, content_type="application/json") @api_view(['GET', 'POST']) @@ -102,9 +103,8 @@ def lab_analyses(request, org_id, format=None): if request.method == 'GET': data = get_collection(f"labs/{org_id}/analyses") - return Response({ "data": data}, content_type="application/json") - + return Response({"data": data}, content_type="application/json") + elif request.method == 'POST': # TODO: Create an analysis. - return Response({ "data": "Under construction"}, content_type="application/json") - + return Response({"data": "Under construction"}, content_type="application/json") diff --git a/cannlytics_api/api/leaf_test_api.py b/cannlytics_api/api/leaf_test_api.py index 93a1930..2204e75 100644 --- a/cannlytics_api/api/leaf_test_api.py +++ b/cannlytics_api/api/leaf_test_api.py @@ -1,8 +1,9 @@ -from rest_framework import status +# from rest_framework import status from rest_framework.decorators import api_view from rest_framework.response import Response -from utils.firebase import get_collection, get_document, update_document +# from utils.firebase import get_collection, get_document, update_document +from utils.firebase import get_collection @api_view(['GET', 'POST']) @@ -10,14 +11,16 @@ def lab_results(request, format=None): """Get lab results data.""" if request.method == 'GET': - limit = request.query_params.get("limit", 1000) + limit = request.query_params.get('limit', 1000) if limit: limit = int(limit) - order_by = request.query_params.get("order_by", "") + order_by = request.query_params.get('order_by', '') # TODO: Get any filters from dict(request.query_params) - docs = get_collection('tests/leaf/lab_results', order_by=order_by, limit=limit, filters=[]) - return Response(docs, content_type="application/json") - + docs = get_collection( + 'tests/leaf/lab_results', order_by=order_by, limit=limit, filters=[] + ) + return Response(docs, content_type='application/json') + if request.method == 'POST': print('TODO: Create lab results') return NotImplementedError @@ -28,12 +31,13 @@ def mmes(request, format=None): """Get licensee (MME) data.""" if request.method == 'GET': - limit = request.query_params.get("limit", None) + limit = request.query_params.get('limit', None) if limit: limit = int(limit) - order_by = request.query_params.get("order_by", "") + order_by = request.query_params.get('order_by', '') # TODO: Get any filters from dict(request.query_params) - # e.g. {"key": "name", "operation": "==", "value": "xyz"} - docs = get_collection('tests/leaf/mmes', order_by=order_by, limit=limit, filters=[]) - return Response(docs, content_type="application/json") - + # e.g. {'key': 'name', 'operation': '==', 'value': 'xyz'} + docs = get_collection( + 'tests/leaf/mmes', order_by=order_by, limit=limit, filters=[] + ) + return Response(docs, content_type='application/json') diff --git a/cannlytics_api/api/users.py b/cannlytics_api/api/users.py index 9f2e00e..4b1137c 100644 --- a/cannlytics_api/api/users.py +++ b/cannlytics_api/api/users.py @@ -1,10 +1,11 @@ - from datetime import datetime -from rest_framework import status + +# from rest_framework import status from rest_framework.decorators import api_view from rest_framework.response import Response -from .auth import authenticate -from utils.firebase import get_document, update_document + +# from .auth import authenticate +# from utils.firebase import get_document, update_document @api_view(['GET', 'POST']) @@ -13,30 +14,31 @@ def users(request, format=None): # try: # claims = authenticate(request) # except: - # return Response({"error": "Could not authenticate."}, status=status.HTTP_400_BAD_REQUEST) + # return Response({'error': 'Could not authenticate.'}, + # status=status.HTTP_400_BAD_REQUEST) # Get user(s). if request.method == 'GET': - print("Getting user...") - # limit = request.query_params.get("limit", None) - # order_by = request.query_params.get("order_by", "state") + print('Getting user...') + # limit = request.query_params.get('limit', None) + # order_by = request.query_params.get('order_by', 'state') # # TODO: Get any filters from dict(request.query_params) # labs = get_collection('labs', order_by=order_by, limit=limit, filters=[]) user = {} - return Response({ "data": user}, content_type="application/json") + return Response({'data': user}, content_type='application/json') # Update or create user(s). elif request.method == 'POST': # TODO: Check if user already exists. # get_document - print("Creating a user...") + print('Creating a user...') timestamp = datetime.now().isoformat() - email = request.query_params.get("email", "") + email = request.query_params.get('email', '') user = { - "email": email, - "created_at": timestamp, - # "uid": user.uid, - "photo_url": f"https://robohash.org/${email}?set=set5", + 'email': email, + 'created_at': timestamp, + # 'uid': user.uid, + 'photo_url': f'https://robohash.org/${email}?set=set5', } print(user) - return Response({ "success": True}, content_type="application/json") \ No newline at end of file + return Response({'success': True}, content_type='application/json') diff --git a/cannlytics_api/settings.py b/cannlytics_api/settings.py index a28c90c..fe157ad 100644 --- a/cannlytics_api/settings.py +++ b/cannlytics_api/settings.py @@ -8,23 +8,24 @@ import environ import os -#------------------------------------------------------------# +# ------------------------------------------------------------# # Project variables. -#------------------------------------------------------------# +# ------------------------------------------------------------# PROJECT_NAME = "cannlytics_api" ROOT_URLCONF = "cannlytics_api.urls" SETTINGS_NAME = "cannlytics_api_settings" WSGI_APPLICATION = "cannlytics_api.wsgi.application" BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -#------------------------------------------------------------# +# ------------------------------------------------------------# # Environment variables # https://docs.djangoproject.com/en/3.1/ref/settings/#secret-key -#------------------------------------------------------------# +# ------------------------------------------------------------# env_file = os.path.join(BASE_DIR, ".env") if not os.path.isfile(".env"): import google.auth from google.cloud import secretmanager as sm + _, project = google.auth.default() if project: client = sm.SecretManagerServiceClient() @@ -37,10 +38,10 @@ SECRET_KEY = env("SECRET_KEY") DEBUG = env("DEBUG") -#------------------------------------------------------------# +# ------------------------------------------------------------# # Apps # https://docs.djangoproject.com/en/3.1/ref/applications/ -#------------------------------------------------------------# +# ------------------------------------------------------------# INSTALLED_APPS = [ "cannlytics_api", "django.contrib.admin", @@ -51,10 +52,10 @@ "rest_framework", ] -#------------------------------------------------------------# +# ------------------------------------------------------------# # Middleware # https://docs.djangoproject.com/en/3.1/topics/http/middleware/ -#------------------------------------------------------------# +# ------------------------------------------------------------# MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", @@ -65,10 +66,10 @@ "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -#------------------------------------------------------------# +# ------------------------------------------------------------# # Templates # https://docs.djangoproject.com/en/3.1/ref/templates/language/ -#------------------------------------------------------------# +# ------------------------------------------------------------# TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", @@ -80,25 +81,25 @@ "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", - ], + ] }, - }, + } ] -#------------------------------------------------------------# +# ------------------------------------------------------------# # Internationalization # https://docs.djangoproject.com/en/3.1/topics/i18n/ -#------------------------------------------------------------# +# ------------------------------------------------------------# LANGUAGE_CODE = "en-us" TIME_ZONE = "America/Los_Angeles" USE_I18N = True USE_L10N = True USE_TZ = True -#------------------------------------------------------------# +# ------------------------------------------------------------# # Security # https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/web_application_security -#------------------------------------------------------------# +# ------------------------------------------------------------# ALLOWED_HOSTS = [ "*", # TODO: DANGEROUS! Remove in production. "localhost:8000", @@ -109,10 +110,10 @@ SECURE_SSL_REDIRECT = False -#------------------------------------------------------------# +# ------------------------------------------------------------# # Database # https://docs.djangoproject.com/en/3.1/ref/settings/#databases -#------------------------------------------------------------# +# ------------------------------------------------------------# DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", diff --git a/cannlytics_api/urls.py b/cannlytics_api/urls.py index 1ec55e6..b479d42 100644 --- a/cannlytics_api/urls.py +++ b/cannlytics_api/urls.py @@ -2,7 +2,7 @@ from rest_framework.urlpatterns import format_suffix_patterns from rest_framework import routers from . import views -from .api import labs, users, leaf_test_api, cannlypedia +from .api import labs, leaf_test_api, cannlypedia # Change URLs to not end in a trailing slash. # https://stackoverflow.com/questions/46163838/how-can-i-make-a-trailing-slash-optional-on-a-django-rest-framework-simplerouter @@ -10,17 +10,14 @@ app_name = "cannlytics_api" urlpatterns = [ - # Base endpoints path("", views.index, name="index"), path("v1/", views.base, name="base"), - # Lab endpoints path("v1/labs/", labs.labs), path("v1/labs//", labs.lab), path("v1/labs//analyses/", labs.lab_analyses), path("v1/labs//logs/", labs.lab_logs), - # Leaf test endpoints path("test/leaf/mmes/", leaf_test_api.mmes), path("test/leaf/lab_results/", leaf_test_api.lab_results), @@ -28,30 +25,20 @@ # path("/test/leaf/areas"), # path("/test/leaf/areas/update"), # path("/test/leaf/strains"), - # TODO: Better handle 404's - # User endpoints # path("v1/users/", users.users), # path("v1/users//", users.users), - # TODO: Build out additional endpoints - # /regulations - # /instruments - # /analytes - # /instruments - # /lab_results - # Optional: Find a way to generalize # path("v1//", views.get_labs, name="endpoint"), - # Functional - path('scholars/', cannlypedia.scholars), + path("scholars/", cannlypedia.scholars), ] # Adding optional format suffixes to our URLs diff --git a/cannlytics_api/views.py b/cannlytics_api/views.py index a3ff7bd..d718172 100644 --- a/cannlytics_api/views.py +++ b/cannlytics_api/views.py @@ -12,50 +12,51 @@ from rest_framework.response import Response from utils.firebase import get_collection, get_document, update_document -BASE = "https://api.cannlytics.com" -ENDPOINTS = ["labs"] -VERSION = "v1" +BASE = 'https://api.cannlytics.com' +ENDPOINTS = ['labs'] +VERSION = 'v1' -#----------------------------------------------# +# ----------------------------------------------# # API helpers -#----------------------------------------------# +# ----------------------------------------------# def authenticate(request): - """ Identify the user's Firebase account using an ID token. """ - authorization = request.headers["Authorization"] + """Identify the user's Firebase account using an ID token.""" + authorization = request.headers['Authorization'] token = authorization.split(' ')[1] claims = auth.verify_id_token(token) uid = claims['uid'] - request.session['uid'] = uid # Save user's custom claims in a session? + request.session['uid'] = uid # Save user's custom claims in a session? return claims -#----------------------------------------------# +# ----------------------------------------------# # Base endpoints -#----------------------------------------------# +# ----------------------------------------------# @api_view(['GET']) def index(request, format=None): """Informational base endpoint.""" - message = f"Welcome to the Cannlytics API. The current version is {VERSION} and is located at {BASE}/{VERSION}." - return Response({ "message": message}, content_type="application/json") + message = 'Welcome to the Cannlytics API.' + message += f'The current version is {VERSION} and is located at {BASE}/{VERSION}.' + return Response({'message': message}, content_type='application/json') @api_view(['GET']) def base(request, format=None): """Informational version endpoint.""" - message = f"Welcome to {VERSION} of the Cannlytics API. Available endpoints:\n\n" + message = f'Welcome to {VERSION} of the Cannlytics API. Available endpoints:\n\n' for endpoint in ENDPOINTS: - message += f"{endpoint}\n" - return Response({ "message": message}, content_type="application/json") + message += f'{endpoint}\n' + return Response({'message': message}, content_type='application/json') -#----------------------------------------------# +# ----------------------------------------------# # User endpoints -#----------------------------------------------# +# ----------------------------------------------# @api_view(['GET', 'POST']) @@ -64,23 +65,23 @@ def users(request, format=None): # Get user(s). if request.method == 'GET': - print("Getting user...") - # limit = request.query_params.get("limit", None) - # order_by = request.query_params.get("order_by", "state") + print('Getting user...') + # limit = request.query_params.get('limit', None) + # order_by = request.query_params.get('order_by', 'state') # # TODO: Get any filters from dict(request.query_params) # labs = get_collection('labs', order_by=order_by, limit=limit, filters=[]) user = {} - return Response({ "data": user}, content_type="application/json") + return Response({'data': user}, content_type='application/json') # Update or create user(s). elif request.method == 'POST': - print("Creating a user...") - return Response({ "success": True}, content_type="application/json") + print('Creating a user...') + return Response({'success': True}, content_type='application/json') -#----------------------------------------------# +# ----------------------------------------------# # Lab endpoints -#----------------------------------------------# +# ----------------------------------------------# @api_view(['GET', 'POST']) @@ -89,11 +90,11 @@ def labs(request, format=None): # Query labs. if request.method == 'GET': - limit = request.query_params.get("limit", None) - order_by = request.query_params.get("order_by", "state") + limit = request.query_params.get('limit', None) + order_by = request.query_params.get('order_by', 'state') # TODO: Get any filters from dict(request.query_params) labs = get_collection('labs', order_by=order_by, limit=limit, filters=[]) - return Response({ "data": labs}, content_type="application/json") + return Response({'data': labs}, content_type='application/json') # Update a lab given a valid Firebase token. elif request.method == 'POST': @@ -101,44 +102,46 @@ def labs(request, format=None): # Check token. try: claims = authenticate(request) - except: - return Response({"error": "Could not authenticate."}, status=status.HTTP_400_BAD_REQUEST) + except Exception: # TODO: what is the actual exception? + return Response( + {'error': 'Could not authenticate.'}, status=status.HTTP_400_BAD_REQUEST + ) # Get the posted lab data. lab = request.data - org_id = lab["id"] - lab["slug"] = slugify(lab["name"]) + org_id = lab['id'] + lab['slug'] = slugify(lab['name']) # TODO: Handle adding labs. # Create uuid, latitude, and longitude, other fields? # Determine any changes. - existing_data = get_document(f"labs/{org_id}") + existing_data = get_document(f'labs/{org_id}') changes = [] for key, after in lab: before = existing_data[key] if before != after: - changes.append({"key": key, "before": before, "after": after}) - + changes.append({'key': key, 'before': before, 'after': after}) + # Get a timestamp. timestamp = datetime.now().isoformat() - lab["updated_at"] = timestamp + lab['updated_at'] = timestamp # Create a change log. log_entry = { - "action": "Updated lab data.", - "type": "change", - "created_at": lab["updated_at"], - "user": claims["uid"], - "user_name": claims["display_name"], - "user_email": claims["email"], - "photo_url": claims["photo_url"], - "changes": changes, + 'action': 'Updated lab data.', + 'type': 'change', + 'created_at': lab['updated_at'], + 'user': claims['uid'], + 'user_name': claims['display_name'], + 'user_email': claims['email'], + 'photo_url': claims['photo_url'], + 'changes': changes, } - update_document(f"labs/{org_id}/logs/{timestamp}", log_entry) + update_document(f'labs/{org_id}/logs/{timestamp}', log_entry) # Update the lab. - update_document(f"labs/{org_id}", lab) + update_document(f'labs/{org_id}', lab) return Response(log_entry, status=status.HTTP_201_CREATED) @@ -148,13 +151,12 @@ def lab_logs(request, org_id, format=None): """Get or create lab logs.""" if request.method == 'GET': - data = get_collection(f"labs/{org_id}/logs") - return Response({ "data": data}, content_type="application/json") - + data = get_collection(f'labs/{org_id}/logs') + return Response({'data': data}, content_type='application/json') + elif request.method == 'POST': # TODO: Create a log. - return Response({ "data": "Under construction"}, content_type="application/json") - + return Response({'data': 'Under construction'}, content_type='application/json') @api_view(['GET', 'POST']) @@ -164,12 +166,12 @@ def lab_analyses(request, org_id, format=None): """ if request.method == 'GET': - data = get_collection(f"labs/{org_id}/analyses") - return Response({ "data": data}, content_type="application/json") - + data = get_collection(f'labs/{org_id}/analyses') + return Response({'data': data}, content_type='application/json') + elif request.method == 'POST': # TODO: Create an analysis. - return Response({ "data": "Under construction"}, content_type="application/json") + return Response({'data': 'Under construction'}, content_type='application/json') # TODO: diff --git a/cloudmigrate.yaml b/cloudmigrate.yaml index 5ea95ea..be98d65 100644 --- a/cloudmigrate.yaml +++ b/cloudmigrate.yaml @@ -13,4 +13,4 @@ steps: # - name: "gcr.io/google-appengine/exec-wrapper" # args: ["-i", "gcr.io/cannlytics/cannlytics-website", # "-s", "cannlytics:us-central1:cannlytics-sql", -# "--", "python", "manage.py", "collectstatic", "--no-input"] \ No newline at end of file +# "--", "python", "manage.py", "collectstatic", "--no-input"] diff --git a/public/robots.txt b/public/robots.txt index ea00025..8dad365 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -2,4 +2,4 @@ User-agent: * Allow: / -Sitemap: https://www.api.cannlytics.com/sitemap.xml \ No newline at end of file +Sitemap: https://www.api.cannlytics.com/sitemap.xml diff --git a/public/sitemap.xml b/public/sitemap.xml index 7b5c82e..011c9b8 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -11,4 +11,4 @@ 1.00 - \ No newline at end of file + diff --git a/tests/test_get_scholars.py b/tests/test_get_scholars.py index 7b7fad9..c40a089 100644 --- a/tests/test_get_scholars.py +++ b/tests/test_get_scholars.py @@ -16,8 +16,8 @@ import urllib # Cannlytics API and API scholars endpoint. -url = 'https://api.cannlytics.com/' # Production -url = 'http://127.0.0.1:4200/' # Dev +url = 'https://api.cannlytics.com/' # Production +url = 'http://127.0.0.1:4200/' # Dev endpoint = 'scholars/' expected_result = { diff --git a/tests/test_labs_endpoints.py b/tests/test_labs_endpoints.py index 825b7ee..95ce37a 100644 --- a/tests/test_labs_endpoints.py +++ b/tests/test_labs_endpoints.py @@ -15,8 +15,8 @@ import requests -BASE = "http://127.0.0.1:4200/" -ENDPOINTS = ["", "/labs"] +BASE = 'http://127.0.0.1:4200/' +ENDPOINTS = ['', '/labs'] # TODO: Test authenticate. @@ -43,8 +43,7 @@ def test_endpoints(target_endpoints, expected_result): """Request each endpoint, expecting responses with 200 status code.""" metadata = [] for endpoint in ENDPOINTS: - url = os.path.join(BASE, endpoint) + url = os.path.join(BASE, endpoint) response = requests.get(url) metadata.append(response.status_code) assert metadata == expected_result - diff --git a/tests/test_users_endpoints.py b/tests/test_users_endpoints.py index c32db79..15757ed 100644 --- a/tests/test_users_endpoints.py +++ b/tests/test_users_endpoints.py @@ -10,7 +10,7 @@ There is NO WARRANTY, to the extent permitted by law. Description: - + Resources: @@ -18,8 +18,8 @@ import os import requests -BASE = "http://127.0.0.1:4200/" +BASE = 'http://127.0.0.1:4200/' endpoint = 'users' -url = os.path.join(BASE, endpoint) -response = requests.post(url, {'email': 'contact@cannlytics.com'}) \ No newline at end of file +url = os.path.join(BASE, endpoint) +response = requests.post(url, {'email': 'contact@cannlytics.com'}) diff --git a/utils/firebase.py b/utils/firebase.py index 985edfb..5c0d6a4 100644 --- a/utils/firebase.py +++ b/utils/firebase.py @@ -11,15 +11,15 @@ initialize_app() -#------------------------------------------------------------# +# ------------------------------------------------------------# # Firestore helpers -#------------------------------------------------------------# +# ------------------------------------------------------------# def create_reference(database, reference): """Create a database reference for a given path.""" ref = database - parts = reference.split('/') + parts = reference.split("/") for i in range(len(parts)): part = parts[i] if i % 2: @@ -31,7 +31,7 @@ def create_reference(database, reference): def get_keywords(string): """Get keywords for a given string.""" - keywords = string.lower().split(' ') + keywords = string.lower().split(" ") keywords = list(filter("", keywords)) return keywords @@ -75,23 +75,25 @@ def get_collection(ref, limit=None, order_by=None, desc=False, filters=[]): collection = create_reference(database, ref) if filters: for filter in filters: - collection = collection.where(filter["key"], filter["operation"], filter["value"]) + collection = collection.where( + filter["key"], filter["operation"], filter["value"] + ) if order_by and desc: - collection = collection.order_by(order_by, direction='DESCENDING') + collection = collection.order_by(order_by, direction="DESCENDING") elif order_by: collection = collection.order_by(order_by) if limit: collection = collection.limit(limit) - query = collection.stream() # Only handles streams less than 2 mins. + query = collection.stream() # Only handles streams less than 2 mins. for doc in query: data = doc.to_dict() docs.append(data) return docs -#------------------------------------------------------------# +# ------------------------------------------------------------# # Authentication helpers -#------------------------------------------------------------# +# ------------------------------------------------------------# def create_account(name, email, notification=True): @@ -99,7 +101,7 @@ def create_account(name, email, notification=True): Given user name and email, create an account if the email isn't being used by an existing account. """ - chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$-_' + chars = "abcdefghijklmnopqrstuvwxyz0123456789!@#$-_" password = get_random_string(42, chars) # Optional: Try to get photo_url from gravatar. try: @@ -110,38 +112,29 @@ def create_account(name, email, notification=True): password=password, display_name=name, photo_url=None, - disabled=False + disabled=False, ) return user, password - except: + except Exception: # TODO: what is the actual exception? return None, None -#------------------------------------------------------------# +# ------------------------------------------------------------# # Storage helpers -#------------------------------------------------------------# +# ------------------------------------------------------------# def download_file(source_blob_name, destination_file_name): """Downloads a file from Firebase Storage.""" - bucket = storage.bucket(name="cannlytics.appspot.com") # TODO: Get from .env + bucket = storage.bucket(name="cannlytics.appspot.com") # TODO: Get from .env blob = bucket.blob(source_blob_name) blob.download_to_filename(destination_file_name) - print( - "Blob {} downloaded to {}.".format( - source_blob_name, destination_file_name - ) - ) + print("Blob {} downloaded to {}.".format(source_blob_name, destination_file_name)) def upload_file(destination_blob_name, source_file_name): """Upload file to Firebase Storage.""" - bucket = storage.bucket(name="cannlytics.appspot.com") # TODO: Get from .env + bucket = storage.bucket(name="cannlytics.appspot.com") # TODO: Get from .env blob = bucket.blob(destination_blob_name) blob.upload_from_filename(source_file_name) - print( - "File {} uploaded to {}.".format( - source_file_name, destination_blob_name - ) - ) - + print("File {} uploaded to {}.".format(source_file_name, destination_blob_name))