diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml
index 4271b92c..61ebfd5b 100644
--- a/.github/workflows/cicd.yml
+++ b/.github/workflows/cicd.yml
@@ -195,7 +195,7 @@ jobs:
commit_hash: ${{ needs.context.outputs.commit_hash }}
git_repo_branch: ${{ needs.context.outputs.git_repo_branch }}
gh_auth_token: ${{ secrets.GH_AUTH_TOKEN }}
- app_instance: eval
+ app_instance: dev
- name: 'Surface context from executed build step'
id: context
diff --git a/.gitignore b/.gitignore
index 6cdf7358..1177047d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,9 @@ spotseeker_web
# IDE files
.idea/
+# vscode files
+.vscode/
+
# pipenv
Pipfile
Pipfile.lock
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 00f0db18..1a55804f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-ARG DJANGO_CONTAINER_VERSION=1.3.8
+ARG DJANGO_CONTAINER_VERSION=1.4.1
FROM gcr.io/uwit-mci-axdd/django-container:${DJANGO_CONTAINER_VERSION} as app-container
diff --git a/docker-compose.yml b/docker-compose.yml
index f03b8ef0..8dbbc03c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -11,7 +11,7 @@ services:
- "${PORT:-8000}:8000"
environment:
ENV: localdev
- AUTH_MODULE: ${AUTH_MODULE:-all_ok}
+ SPOTSEEKER_OAUTH_ENABLED: ${SPOTSEEKER_OAUTH_ENABLED}
SPOTSEEKER_AUTH_ADMINS: ${SPOTSEEKER_AUTH_ADMINS}
SPOTSEEKER_WEB_SERVER_HOST: ${SPOTSEEKER_WEB_SERVER_HOST}
SPOTSEEKER_WEB_OAUTH_KEY: ${SPOTSEEKER_WEB_OAUTH_KEY}
diff --git a/docker/dev-values.yml b/docker/dev-values.yml
new file mode 100644
index 00000000..a4cfef1c
--- /dev/null
+++ b/docker/dev-values.yml
@@ -0,0 +1,156 @@
+autoscaling:
+ enabled: false
+ minReplicas: 1
+ maxReplicas: 1
+ingress:
+ enabled: true
+ tls:
+ spotseeker:
+ secretName: dev.api.scout.uw.edu-ingress-cert
+ hosts:
+ - dev.api.scout.uw.edu
+ hosts:
+ spotseeker:
+ host: dev.api.scout.uw.edu
+ paths:
+ - "/"
+ annotations:
+ cert-manager.io/cluster-issuer: letsencrypt
+ nginx.ingress.kubernetes.io/client-body-buffer-size: "16K"
+ nginx.ingress.kubernetes.io/proxy-body-size: "20m"
+ nginx.ingress.kubernetes.io/proxy-read-timeout: "500"
+ nginx.ingress.kubernetes.io/ssl-ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256"
+lifecycle:
+ enabled: true
+ preStop:
+ enabled: true
+affinity:
+ podsSpanNodes: true
+readiness:
+ enabled: true
+securityPolicy:
+ enabled: true
+externalService:
+ enabled: true
+ name: spotseeker-dev-db-service
+ type: ClusterIP
+ serviceAddress: 172.18.0.196
+ servicePort: 3306
+database:
+ engine: mysql
+ name: api_dev
+ hostname: spotseeker-dev-db-service
+ secretName: dev.api.scout.uw.edu-sql-secrets
+repo: spotseeker
+instance: dev
+image:
+ repository: gcr.io/uwit-mci-axdd/spotseeker
+ tag: IMAGE_TAG
+memcached:
+ enabled: true
+ replicaCount: 1
+ updateStrategy:
+ type: RollingUpdate
+gcsCredentials:
+ mounted: true
+ secretName: dev.api.scout.uw.edu-gc-service-credentials
+cronjob:
+ enabled: false
+ jobs:
+ - name: sync-techloan
+ schedule: "0,15,30,45 * * * *"
+ command: ["/scripts/management_command.sh"]
+ args: ["sync_techloan"]
+daemon:
+ enabled: false # cronjob is probably more appropriate
+ daemons:
+ - name: sync-techloan
+ replicaCount: 1
+ command: ["/scripts/management_daemon.sh"]
+ args: ["--delay", "300", "sync_techloan"]
+environmentVariables:
+ - name: AUTH_MODULE
+ value: oauth
+ - name: CLUSTER_CNAME
+ value: dev.api.scout.uw.edu
+ - name: ENV
+ value: dev
+ - name: WEBSERVER
+ value: nginx
+ - name: CACHE_MAX_ENTRIES
+ value: "1000"
+ - name: CACHE_TIMEOUT
+ value: "86400"
+externalSecrets:
+ enabled: true
+ secrets:
+ - name: dev.api.scout.uw.edu-secrets
+ externalKey: axdd/kv/data/scout/dev-api/secrets
+ data:
+ - name: django-secret
+ property: django-secret
+ - name: spotseeker-auth-admins
+ property: spotseeker-auth-admins
+ - name: storage-bucket-name
+ property: storage-bucket-name
+ - name: storage-project-id
+ property: storage-project-id
+ - name: spotseeker-techloan-url
+ property: spotseeker-techloan-url
+ - name: spotseeker-web-server-host
+ property: spotseeker-web-server-host
+ - name: spotseeker-web-oauth-key
+ property: spotseeker-web-oauth-key
+ - name: spotseeker-web-oauth-secret
+ property: spotseeker-web-oauth-secret
+ - name: spotseeker-web-oauth-user
+ property: spotseeker-web-oauth-user
+ - name: dev.api.scout.uw.edu-sql-secrets
+ externalKey: axdd/kv/data/scout/common/sql-secrets
+ data:
+ - name: username
+ property: username
+ - name: password
+ property: password
+ - name: dev.api.scout.uw.edu-gc-service-credentials
+ externalKey: axdd/kv/data/scout/common/gc-service-credentials
+ data:
+ - name: credentials.json
+ property: credentials.json
+environmentVariablesSecrets:
+ djangoSecret:
+ name: DJANGO_SECRET
+ secretName: dev.api.scout.uw.edu-secrets
+ secretKey: django-secret
+ spotseekerAuthAdmins:
+ name: SPOTSEEKER_AUTH_ADMINS
+ secretName: dev.api.scout.uw.edu-secrets
+ secretKey: spotseeker-auth-admins
+ storageBucketName:
+ name: STORAGE_BUCKET_NAME
+ secretName: dev.api.scout.uw.edu-secrets
+ secretKey: storage-bucket-name
+ storageProjectId:
+ name: STORAGE_PROJECT_ID
+ secretName: dev.api.scout.uw.edu-secrets
+ secretKey: storage-project-id
+ spotseekerTechloanUrl:
+ name: SPOTSEEKER_TECHLOAN_URL
+ secretName: dev.api.scout.uw.edu-secrets
+ secretKey: spotseeker-techloan-url
+ spotseekerWebServerHost:
+ name: SPOTSEEKER_WEB_SERVER_HOST
+ secretName: dev.api.scout.uw.edu-secrets
+ secretKey: spotseeker-web-server-host
+ spotseekerWebOauthKey:
+ name: SPOTSEEKER_WEB_OAUTH_KEY
+ secretName: dev.api.scout.uw.edu-secrets
+ secretKey: spotseeker-web-oauth-key
+ spotseekerWebOauthSecret:
+ name: SPOTSEEKER_WEB_OAUTH_SECRET
+ secretName: dev.api.scout.uw.edu-secrets
+ secretKey: spotseeker-web-oauth-secret
+ spotseekerWebOauthUser:
+ name: SPOTSEEKER_WEB_OAUTH_USER
+ secretName: dev.api.scout.uw.edu-secrets
+ secretKey: spotseeker-web-oauth-user
diff --git a/docker/prod-values.yml b/docker/prod-values.yml
index 132dfc9e..cc092111 100644
--- a/docker/prod-values.yml
+++ b/docker/prod-values.yml
@@ -71,8 +71,8 @@ daemon:
command: ["/scripts/management_daemon.sh"]
args: ["--delay", "300", "sync_techloan"]
environmentVariables:
- - name: AUTH_MODULE
- value: oauth
+ - name: SPOTSEEKER_OAUTH_ENABLED
+ value: true
- name: CLUSTER_CNAME
value: api.scout.uw.edu
- name: ENV
diff --git a/docker/settings.py b/docker/settings.py
index 7d44a69d..c8e0c492 100644
--- a/docker/settings.py
+++ b/docker/settings.py
@@ -8,15 +8,36 @@
DEBUG = False
INSTALLED_APPS += [
- "oauth_provider",
"spotseeker_server",
+ "oauth2_provider",
+ "corsheaders",
"django_extensions",
]
MIDDLEWARE += [
"spotseeker_server.logger.oauth.LogMiddleware",
+ "corsheaders.middleware.CorsMiddleware",
]
+AUTH_USER_MODEL = "spotseeker_server.Client"
+
+AUTHENTICATION_BACKENDS = (
+ "oauth2_provider.backends.OAuth2Backend",
+ "django.contrib.auth.backends.ModelBackend",
+)
+
+CORS_ORIGIN_ALLOW_ALL = DEBUG
+if os.getenv("ENV", "localdev") == "prod":
+ CORS_ALLOWED_ORIGINS = [
+ "https://scout.uw.edu",
+ "https://manager.scout.uw.edu",
+ ]
+else:
+ CORS_ALLOWED_ORIGINS = [
+ "https://test.scout.uw.edu",
+ "https://test.manager.scout.uw.edu",
+ ]
+
# django storages settings
if not DEBUG:
DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
@@ -28,9 +49,11 @@
"/gcs/credentials.json"
)
-SPOTSEEKER_AUTH_MODULE = "spotseeker_server.auth.{}".format(
- os.getenv("AUTH_MODULE", "all_ok")
-)
+SPOTSEEKER_OAUTH_ENABLED = os.getenv("SPOTSEEKER_OAUTH_ENABLED", not DEBUG)
+# convert string to boolean if set in .env
+if type(SPOTSEEKER_OAUTH_ENABLED) == str:
+ SPOTSEEKER_OAUTH_ENABLED = SPOTSEEKER_OAUTH_ENABLED.lower() == "true"
+
# turn string of auth admins into list
SPOTSEEKER_AUTH_ADMINS = (
os.getenv("SPOTSEEKER_AUTH_ADMINS", "").replace(" ", "").split(",")
@@ -60,7 +83,8 @@
}
}
else:
- # The various MEMCACHED variables are set in django-container's base_settings/common.py
+ # The various MEMCACHED variables are set in django-container's
+ # base_settings/common.py
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
diff --git a/docker/test-values.yml b/docker/test-values.yml
index e64f48c4..2f158c68 100644
--- a/docker/test-values.yml
+++ b/docker/test-values.yml
@@ -65,8 +65,8 @@ daemon:
command: ["/scripts/management_daemon.sh"]
args: ["--delay", "300", "sync_techloan"]
environmentVariables:
- - name: AUTH_MODULE
- value: oauth
+ - name: SPOTSEEKER_OAUTH_ENABLED
+ value: true
- name: CLUSTER_CNAME
value: test.api.scout.uw.edu
- name: ENV
diff --git a/docker/urls.py b/docker/urls.py
index 4816c0b9..954c31d1 100644
--- a/docker/urls.py
+++ b/docker/urls.py
@@ -1,34 +1,24 @@
-"""docker URL Configuration
+# Copyright 2024 UW-IT, University of Washington
+# SPDX-License-Identifier: Apache-2.0
-The `urlpatterns` list routes URLs to views. For more information please see:
- https://docs.djangoproject.com/en/1.11/topics/http/urls/
-Examples:
-Function views
- 1. Add an import: from my_app import views
- 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
-Class-based views
- 1. Add an import: from other_app.views import Home
- 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
-Including another URLconf
- 1. Import the include() function: from django.conf.urls import url, include
- 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
-"""
+from .base_urls import *
from django.conf import settings
-from django.conf.urls import url, include
+from django.urls import path, include
+from django.contrib import admin
-urlpatterns = [
- url(r'^auth/', include('oauth_provider.urls')),
- url(r'^api/', include('spotseeker_server.urls')),
- url(r'^', include('django_prometheus.urls')), # add here for django 1.11 compatibility
+urlpatterns += [
+ path("api/", include("spotseeker_server.urls")),
+ path(
+ "auth/", include("oauth2_provider.urls", namespace="oauth2_provider")
+ ),
]
if settings.DEBUG:
- from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += [
- url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
- url(r'^admin/', include(admin.site.urls)),
+ path("admin/doc/", include("django.contrib.admindocs.urls")),
+ path("admin/", admin.site.urls),
]
urlpatterns += staticfiles_urlpatterns()
diff --git a/requirements.txt b/requirements.txt
index 50e7d025..b009075c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,5 @@
# these two can be upgraded when django gets an update
mysqlclient~=1.3
-django-prometheus~=2.0
+# this is temporary for testing migrations in upgrade
+django-extensions==2.2.*
-e .
diff --git a/spotseeker_server/management/commands/resources/building3.jpg b/resources/building3.jpg
similarity index 100%
rename from spotseeker_server/management/commands/resources/building3.jpg
rename to resources/building3.jpg
diff --git a/spotseeker_server/management/commands/resources/building4.jpg b/resources/building4.jpg
similarity index 100%
rename from spotseeker_server/management/commands/resources/building4.jpg
rename to resources/building4.jpg
diff --git a/spotseeker_server/management/commands/resources/building5.jpg b/resources/building5.jpg
similarity index 100%
rename from spotseeker_server/management/commands/resources/building5.jpg
rename to resources/building5.jpg
diff --git a/spotseeker_server/management/commands/resources/building6.jpg b/resources/building6.jpg
similarity index 100%
rename from spotseeker_server/management/commands/resources/building6.jpg
rename to resources/building6.jpg
diff --git a/sample.env b/sample.env
index a83a617d..f4947571 100644
--- a/sample.env
+++ b/sample.env
@@ -3,11 +3,13 @@
# Port to connect to with your browser
#PORT=8001
-# Whether to use all_ok (default) or oauth auth module
-#AUTH_MODULE=oauth
-
# Comma separated list of admins
#SPOTSEEKER_AUTH_ADMINS=javerage,demo_user
+# enabled oauth (True or False)
+#SPOTSEEKER_OAUTH_ENABLED=True
+
# URL to sync techloan from sync_techloan management command
-#SPOTSEEKER_TECHLOAN_URL=https://EXAMPLE_DOMAIN/techloan/api/v2/type/?embed=availability&embed=class
\ No newline at end of file
+#SPOTSEEKER_TECHLOAN_URL=https://EXAMPLE_DOMAIN/techloan/api/v2/type/?embed=availability&embed=class
+
+#ENV=localdev
diff --git a/setup.py b/setup.py
index e807c5af..fcdf66db 100644
--- a/setup.py
+++ b/setup.py
@@ -7,10 +7,12 @@
version="1.0",
description="REST Backend for SpaceScout",
install_requires=[
- "Django==1.11.*",
+ "Django==2.2.*",
"future",
"mock<=1.0.1",
"oauthlib==3.1.*",
+ "django-oauth-toolkit",
+ "django-cors-headers==3.10.*",
"requests==2.26.*",
"requests-oauthlib==1.3.*",
"Pillow",
@@ -18,7 +20,7 @@
"pyproj",
"pytz",
"simplejson>=2.1",
- "django-oauth-plus@git+https://github.com/edx-unsupported/django-oauth-plus#egg=2.2.9.edx-4",
+ "django-oauth-plus@git+https://github.com/abztrakt/django-oauth-plus@spotseeker-changes#egg=2.2.9.edx-4",
"django-storages[google]",
"schema",
"six",
diff --git a/spotseeker_server/__init__.py b/spotseeker_server/__init__.py
index 0cbef36b..47252182 100644
--- a/spotseeker_server/__init__.py
+++ b/spotseeker_server/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
__version__ = "1.0"
diff --git a/spotseeker_server/admin.py b/spotseeker_server/admin.py
index 22007230..2f22683a 100644
--- a/spotseeker_server/admin.py
+++ b/spotseeker_server/admin.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -7,10 +7,8 @@
sbutler1@illinois.edu: use the same forms as used for REST.
"""
-from importlib import import_module
-from django.db import models
from django.contrib import admin
-from django.conf import settings
+from django.contrib.auth.admin import UserAdmin
from spotseeker_server.models import *
from spotseeker_server.forms.spot import SpotForm, SpotExtendedInfoForm
from spotseeker_server.forms.item import ItemForm, ItemExtendedInfoForm
@@ -117,7 +115,7 @@ class SpotExtendedInfoAdmin(admin.ModelAdmin):
admin.site.register(SpotType)
-admin.site.register(TrustedOAuthClient)
+admin.site.register(Client, UserAdmin)
class ItemAdmin(admin.ModelAdmin):
diff --git a/spotseeker_server/auth/__init__.py b/spotseeker_server/auth/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/spotseeker_server/auth/all_ok.py b/spotseeker_server/auth/all_ok.py
deleted file mode 100644
index 74b8fccd..00000000
--- a/spotseeker_server/auth/all_ok.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2023 UW-IT, University of Washington
-# SPDX-License-Identifier: Apache-2.0
-
-""" This module will allow all requests, without requiring authentication or
-authorization. To use it, add this to your settings.py:
-
-SPOTSEEKER_AUTH_MODULE = spotseeker_server.auth.all_ok
-
-By default authenticate_user will use the user demo_user. You can override
-this in settings.py:
-
-SPOTSEEKER_AUTH_ALL_USER = 'other_user'
-"""
-from django.conf import settings
-from django.contrib.auth.models import User
-
-
-def authenticate_application(*args, **kwargs):
- """This always allows requests through"""
- return
-
-
-def authenticate_user(*args, **kwargs):
- """This always allows requests through"""
- request = args[1]
- username = getattr(settings, "SPOTSEEKER_AUTH_ALL_USER", "demo_user")
-
- user_obj = User.objects.get_or_create(username=username)
- request.META["SS_OAUTH_USER"] = username
- return
diff --git a/spotseeker_server/auth/fake_oauth.py b/spotseeker_server/auth/fake_oauth.py
deleted file mode 100644
index 6632ea24..00000000
--- a/spotseeker_server/auth/fake_oauth.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2023 UW-IT, University of Washington
-# SPDX-License-Identifier: Apache-2.0
-
-""" This module will allow all requests, without requiring authentication or
-authorization. To use it, add this to your settings.py:
-
-SPOTSEEKER_AUTH_MODULE = spotseeker_server.auth.fake_oauth
-
-You can specify a user with a request header of ??? (Missing at time of commit)
-"""
-
-from django.contrib import auth
-
-
-def authenticate_application(*args, **kwargs):
- """This always allows requests through"""
- return
-
-
-def authenticate_user(*args, **kwargs):
- """This always allows requests through"""
- request = args[1]
-
- input_username = request.META["TESTING_OAUTH_USER"]
- user = auth.authenticate(remote_user=input_username)
- request.META["SS_OAUTH_USER"] = user.username
- return
diff --git a/spotseeker_server/auth/oauth.py b/spotseeker_server/auth/oauth.py
deleted file mode 100644
index 2310a03f..00000000
--- a/spotseeker_server/auth/oauth.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright 2023 UW-IT, University of Washington
-# SPDX-License-Identifier: Apache-2.0
-
-""" This module uses oauth to allow applications and users access.
-Supports 2-legged oauth for application requests, and for trusted
-applications accessing user-restricted methods. Supports 3-legged
-oauth for non-trusted applications that want to access user methods.
-
-To use this module, add this to your settings.py:
-
-SPOTSEEKER_AUTH_MODULE = spotseeker_server.auth.oauth
-"""
-from django.http import HttpResponse
-
-from oauth_provider.utils import get_oauth_request, verify_oauth_request
-from oauth_provider.store import store, InvalidConsumerError, InvalidTokenError
-from spotseeker_server.models import TrustedOAuthClient
-
-import logging
-
-
-def authenticate_application(*args, **kwargs):
- request = args[1]
- try:
- oauth_request = get_oauth_request(request)
- consumer = store.get_consumer(
- request, oauth_request, oauth_request["oauth_consumer_key"]
- )
- verify_oauth_request(request, oauth_request, consumer)
-
- request.META["SS_OAUTH_CONSUMER_NAME"] = consumer.name
- request.META["SS_OAUTH_CONSUMER_PK"] = consumer.pk
-
- return
- except Exception as e:
- response = HttpResponse("Error authorizing application: %s" % e)
- response.status_code = 401
- return response
-
-
-def authenticate_user(*args, **kwargs):
- request = args[1]
- try:
- oauth_request = get_oauth_request(request)
- consumer = store.get_consumer(
- request, oauth_request, oauth_request["oauth_consumer_key"]
- )
- verify_oauth_request(request, oauth_request, consumer)
-
- # Allow a trusted client to either give us a user via header, or do the
- # 3-legged oauth
- user = None
- try:
- trusted_client = TrustedOAuthClient.objects.get(consumer=consumer)
- if trusted_client and trusted_client.is_trusted:
- user = request.META["HTTP_X_OAUTH_USER"]
- logging.info(
- "user is a trusted client and was set to {}".format(user)
- )
-
- except Exception as e:
- pass
-
- if not user:
- access_token = store.get_access_token(
- request, oauth_request, consumer, oauth_request[u"oauth_token"]
- )
- user = store.get_user_for_access_token(
- request, oauth_request, access_token
- ).username
- logging.info(
- "user was not a trusted client and was set to {}".format(user)
- )
-
- request.META["SS_OAUTH_CONSUMER_NAME"] = consumer.name
- request.META["SS_OAUTH_CONSUMER_PK"] = consumer.pk
- request.META["SS_OAUTH_USER"] = user
-
- return
- except Exception as e:
- response = HttpResponse("Error authorizing user: %s" % e)
- response.status_code = 401
- return response
diff --git a/spotseeker_server/default_forms/item.py b/spotseeker_server/default_forms/item.py
index 6aea1698..3dd7e23d 100644
--- a/spotseeker_server/default_forms/item.py
+++ b/spotseeker_server/default_forms/item.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django import forms
diff --git a/spotseeker_server/default_forms/spot.py b/spotseeker_server/default_forms/spot.py
index 27da155f..d8817d17 100644
--- a/spotseeker_server/default_forms/spot.py
+++ b/spotseeker_server/default_forms/spot.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
diff --git a/spotseeker_server/default_forms/spot_search.py b/spotseeker_server/default_forms/spot_search.py
index ebd863c0..e1c8a1d4 100644
--- a/spotseeker_server/default_forms/spot_search.py
+++ b/spotseeker_server/default_forms/spot_search.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django import forms
diff --git a/spotseeker_server/extras/delimage.py b/spotseeker_server/extras/delimage.py
index 73b8fbe0..762d954c 100644
--- a/spotseeker_server/extras/delimage.py
+++ b/spotseeker_server/extras/delimage.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import getopt
diff --git a/spotseeker_server/extras/uw_server_values.py b/spotseeker_server/extras/uw_server_values.py
index b441c064..977c7ec7 100644
--- a/spotseeker_server/extras/uw_server_values.py
+++ b/spotseeker_server/extras/uw_server_values.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
# This file contains UW specific values on the server side to be localized.
diff --git a/spotseeker_server/fixtures/dummy_oauth.json b/spotseeker_server/fixtures/dummy_oauth.json
index 177661c0..d1215591 100644
--- a/spotseeker_server/fixtures/dummy_oauth.json
+++ b/spotseeker_server/fixtures/dummy_oauth.json
@@ -1,24 +1,11 @@
[
{
- "model": "spotseeker_server.trustedoauthclient",
- "pk": 1,
- "fields": {
- "consumer": 1,
- "is_trusted": true,
- "bypasses_user_authorization": false
- }
-},
-{
- "model": "oauth_provider.consumer",
+ "model": "spotseeker_server.client",
"pk": 1,
"fields": {
"name": "javerage",
- "description": "",
- "key": "dummy",
- "secret": "dummy",
- "status": 1,
- "user": null,
- "xauth_allowed": false
+ "client_id": "dummy",
+ "client_secret": "dummy"
}
}
]
diff --git a/spotseeker_server/forms/item.py b/spotseeker_server/forms/item.py
index 352620e3..75c43783 100644
--- a/spotseeker_server/forms/item.py
+++ b/spotseeker_server/forms/item.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from spotseeker_server.default_forms.item import (
diff --git a/spotseeker_server/forms/spot.py b/spotseeker_server/forms/spot.py
index f7ea9b7d..9014ded1 100644
--- a/spotseeker_server/forms/spot.py
+++ b/spotseeker_server/forms/spot.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
diff --git a/spotseeker_server/forms/spot_search.py b/spotseeker_server/forms/spot_search.py
index 57d125e7..cea11e3f 100644
--- a/spotseeker_server/forms/spot_search.py
+++ b/spotseeker_server/forms/spot_search.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
diff --git a/spotseeker_server/load_module.py b/spotseeker_server/load_module.py
index 60b737d4..40072aa4 100644
--- a/spotseeker_server/load_module.py
+++ b/spotseeker_server/load_module.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from importlib import import_module
diff --git a/spotseeker_server/logger/oauth.py b/spotseeker_server/logger/oauth.py
index c17a5339..20876860 100644
--- a/spotseeker_server/logger/oauth.py
+++ b/spotseeker_server/logger/oauth.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" This creates a log along the lines of the apache
diff --git a/spotseeker_server/management/commands/create_consumer.py b/spotseeker_server/management/commands/create_consumer.py
index 7da25fad..7eff1ce7 100644
--- a/spotseeker_server/management/commands/create_consumer.py
+++ b/spotseeker_server/management/commands/create_consumer.py
@@ -1,20 +1,18 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" This provides a management command to django's manage.py called
-create_consumer that will generate a oauth key and secret based on the consumer
-name.
+create_consumer that will generate a client with a valid credential based on
+the consumer name.
"""
-from optparse import make_option
import hashlib
import random
import string
import time
-from django.core.management.base import BaseCommand, CommandError
-from oauth_provider.models import Consumer
+from django.core.management.base import BaseCommand
-from spotseeker_server.models import TrustedOAuthClient
+from spotseeker_server.models import Client
class Command(BaseCommand):
@@ -25,22 +23,14 @@ class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument(
+ "-n",
"--name",
dest="consumer_name",
- default=False,
help="A name for the consumer",
)
parser.add_argument(
- "--trusted",
- dest="trusted",
- action="store_true",
- default=False,
- help="Makes this consumer trusted "
- "(Adds a TrustedOAuthClient for it)",
- )
-
- parser.add_argument(
+ "-s",
"--silent",
dest="silent",
action="store_true",
@@ -52,29 +42,24 @@ def handle(self, *args, **options):
if options["consumer_name"]:
consumer_name = options["consumer_name"]
else:
- consumer_name = input("Enter consumer name: ")
+ consumer_name = input("Enter client name: ")
+ # key and secret can be anything, but we'll try to keep it unique
key = hashlib.sha1(
"{0} - {1}".format(random.random(), time.time()).encode("utf-8")
).hexdigest()
- # django-oauth-plus now wants secrets to be 16 chars
secret = "".join(
random.choice(string.ascii_letters + string.digits)
for _ in range(16)
)
- consumer = Consumer.objects.create(
- name=consumer_name, key=key, secret=secret
+ client = Client.objects.create(
+ username=consumer_name,
+ name=consumer_name, client_id=key, client_secret=secret
)
-
- if options["trusted"]:
- trusted = TrustedOAuthClient.objects.create(
- consumer=consumer,
- is_trusted=1,
- bypasses_user_authorization=False,
- )
+ credential = client.get_client_credential()
+ client.save()
if not options["silent"]:
- self.stdout.write("Key: %s\n" % key)
- self.stdout.write("Secret: %s\n" % secret)
+ self.stdout.write(f"Credential: {credential}\n")
diff --git a/spotseeker_server/management/commands/create_sample_spots.py b/spotseeker_server/management/commands/create_sample_spots.py
index 855829ee..76886598 100644
--- a/spotseeker_server/management/commands/create_sample_spots.py
+++ b/spotseeker_server/management/commands/create_sample_spots.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
# -*- coding: utf-8 -*-
@@ -6,14 +6,10 @@
create_sample_spots that will generate a set of spots for testing.
"""
from django.core.management.base import BaseCommand, CommandError
-from optparse import make_option
from spotseeker_server.models import *
-from django.contrib.auth.models import User
from django.core.files import File
-from django.utils import timezone
from decimal import *
-# from datetime import datetime
import os
import glob
@@ -48,648 +44,664 @@ def handle(self, *args, **options):
"I'm only going to run if you're sure "
"you want to 'delete my spots'"
)
- else:
- Spot.objects.all().delete()
- SpotExtendedInfo.objects.all().delete()
- SpotAvailableHours.objects.all().delete()
-
- # delete old default images
- base_dir = os.path.dirname(os.path.realpath(__file__))
- path = os.path.join(base_dir, "resources")
- imgs = glob.glob(path + "/building*_*.jpg")
- for img in imgs:
- try:
- os.remove(img)
- except OSError:
- print("Could not delete image: " + img)
-
- lab_space = Spot.objects.create(
- name="This is a computer lab",
- capacity=200,
- longitude=Decimal("-122.306644"),
- latitude=Decimal("47.658241"),
- building_name="Art Building (ART)",
- )
- # get_or_create returns a tuple
- production_studio = SpotType.objects.get_or_create(name="studio")[
- 0
- ]
- # get_or_create returns a tuple
- computer_lab = SpotType.objects.get_or_create(name="computer_lab")[
- 0
- ]
- lab_space.spottypes.add(production_studio)
- lab_space.spottypes.add(computer_lab)
- lab_space.save()
- SpotExtendedInfo.objects.create(
- key="campus", value="seattle", spot=lab_space
- )
- # get_or_create returns a tuple
- cafe_type = SpotType.objects.get_or_create(name="cafe")[0]
- art = Spot.objects.create(
- name="In the Art Building - multiline " "name to test",
- capacity=10,
- longitude=Decimal("-122.306644"),
- latitude=Decimal("47.658241"),
- building_name="Art Building (ART)",
- )
- art.spottypes.add(cafe_type)
- art.save()
- art_ada = SpotExtendedInfo.objects.create(
- key="location_" "description",
- value="This is the " "location of the " "space",
- spot=art,
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="app_type", value="food", spot=art
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="has_whiteboards", value="true", spot=art
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="has_outlets", value="true", spot=art
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="has_displays", value="true", spot=art
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="has_printing", value="true", spot=art
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="has_scanner", value="true", spot=art
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="has_projector", value="true", spot=art
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="has_computers", value="true", spot=art
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="reservable", value="true", spot=art
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="campus", value="seattle", spot=art
- )
- SpotExtendedInfo.objects.create(
- key="access_notes",
- value=" This space reservable "
- "outside of TLC hours. To "
- "reserve, go to http://www."
- "tacoma.uw.edu/library/"
- "reserve-group-study-rooms",
- spot=art,
- )
- SpotExtendedInfo.objects.create(
- key="reservation_notes",
- value=" This space reservable "
- "outside of TLC hours. To "
- "reserve, go to http://www."
- "tacoma.uw.edu/library/"
- "reserve-group-study-rooms",
- spot=art,
- )
- mgr = SpotExtendedInfo.objects.create(
- key="manager", value="ctlt", spot=art
- )
- org = SpotExtendedInfo.objects.create(
- key="organization", value="Art", spot=art
- )
+ Spot.objects.all().delete()
+ SpotExtendedInfo.objects.all().delete()
+ SpotAvailableHours.objects.all().delete()
+
+ # delete old default images
+ imgs = glob.glob("resources/building*_*.jpg")
+ for img in imgs:
+ try:
+ os.remove(img)
+ except OSError:
+ print("Could not delete image: " + img)
+
+ lab_space = Spot.objects.create(
+ name="This is a computer lab",
+ capacity=200,
+ longitude=Decimal("-122.306644"),
+ latitude=Decimal("47.658241"),
+ building_name="Art Building (ART)",
+ )
- art2 = Spot.objects.create(
- name="Also in the Art Building",
- capacity=10,
- longitude=Decimal("-122.306644"),
- latitude=Decimal("47.658241"),
- building_name="Art Building (ART)",
- )
- art2.spottypes.add(cafe_type)
- art2.save()
- art_ada = SpotExtendedInfo.objects.create(
- key="has_whiteboards", value="true", spot=art2
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="has_outlets", value="true", spot=art2
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="has_displays", value="true", spot=art2
- )
- art_ada = SpotExtendedInfo.objects.create(
- key="campus", value="seattle", spot=art2
- )
- mgr = SpotExtendedInfo.objects.create(
- key="manager", value="ctlt", spot=art2
- )
- org = SpotExtendedInfo.objects.create(
- key="organization", value="Art", spot=art2
- )
+ # get_or_create returns a tuple
+ production_studio = SpotType.objects.get_or_create(name="studio")[0]
- base_dir = os.path.dirname(os.path.realpath(__file__))
- f = open(
- os.path.join(base_dir, "resources", "building3.jpg"), "rb"
- )
- art_img1 = SpotImage.objects.create(
- description="This is one " "building",
- spot=art,
- display_index=0,
- image=File(f),
- )
- f = open(
- os.path.join(base_dir, "resources", "building4.jpg"), "rb"
- )
- art_img2 = SpotImage.objects.create(
- description="This is another " "building",
- spot=art,
- display_index=1,
- image=File(f),
- )
- f = open(
- os.path.join(base_dir, "resources", "building5.jpg"), "rb"
- )
- art_img3 = SpotImage.objects.create(
- description="This is a third " "art building",
- spot=art,
- display_index=2,
- image=File(f),
- )
+ # get_or_create returns a tuple
+ computer_lab = SpotType.objects.get_or_create(name="computer_lab")[0]
+ lab_space.spottypes.add(production_studio)
+ lab_space.spottypes.add(computer_lab)
+ lab_space.save()
- f = open(
- os.path.join(base_dir, "resources", "building6.jpg"), "rb"
- )
- art_img4 = SpotImage.objects.create(
- description="This is a third " "art building",
- spot=art,
- display_index=3,
- image=File(f),
- )
+ SpotExtendedInfo.objects.create(
+ key="campus", value="seattle", spot=lab_space
+ )
- study_room_type = SpotType.objects.get_or_create(
- name="study_room"
- )[0]
- tacoma = Spot.objects.create(
- name="WCG #1",
- capacity=20,
- longitude=Decimal("-122.437212"),
- latitude=Decimal("47.246213"),
- building_name="West Coast Grocery " "(WCG)",
- )
- tacoma.spottypes.add(study_room_type)
- tacoma.save()
- wcg_outlets = SpotExtendedInfo.objects.create(
- key="has_outlets", value="true", spot=tacoma
- )
- tacoma_outlets = SpotExtendedInfo.objects.create(
- key="campus", value="tacoma", spot=tacoma
- )
- mgr = SpotExtendedInfo.objects.create(
- key="manager", value="ctlt", spot=tacoma
- )
- org = SpotExtendedInfo.objects.create(
- key="organization", value="Philosophy", spot=tacoma
- )
+ # get_or_create returns a tuple
+ cafe_type = SpotType.objects.get_or_create(name="cafe")[0]
- tacoma2 = Spot.objects.create(
- name="In tacoma - #2",
- capacity=20,
- longitude=Decimal("-122.437708"),
- latitude=Decimal("47.244832"),
- building_name="West Coast Grocery " "(WCG)",
- )
- tacoma2.spottypes.add(study_room_type)
- tacoma2.save()
- tacoma_outlets = SpotExtendedInfo.objects.create(
- key="has_outlets", value="true", spot=tacoma2
- )
- mgr = SpotExtendedInfo.objects.create(
- key="manager", value="ctlt", spot=tacoma2
- )
- mgr = SpotExtendedInfo.objects.create(
- key="campus", value="tacoma", spot=tacoma2
- )
- org = SpotExtendedInfo.objects.create(
- key="organization", value="Economics", spot=tacoma2
- )
+ art = Spot.objects.create(
+ name="In the Art Building - multiline " "name to test",
+ capacity=10,
+ longitude=Decimal("-122.306644"),
+ latitude=Decimal("47.658241"),
+ building_name="Art Building (ART)",
+ )
+ art.spottypes.add(cafe_type)
+ art.save()
+ art_ada = SpotExtendedInfo.objects.create(
+ key="location_" "description",
+ value="This is the " "location of the " "space",
+ spot=art,
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="app_type", value="study", spot=art
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="has_whiteboards", value="true", spot=art
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="has_outlets", value="true", spot=art
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="has_displays", value="true", spot=art
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="has_printing", value="true", spot=art
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="has_scanner", value="true", spot=art
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="has_projector", value="true", spot=art
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="has_computers", value="true", spot=art
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="reservable", value="true", spot=art
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="campus", value="seattle", spot=art
+ )
+ SpotExtendedInfo.objects.create(
+ key="access_notes",
+ value=" This space reservable "
+ "outside of TLC hours. To "
+ "reserve, go to http://www."
+ "tacoma.uw.edu/library/"
+ "reserve-group-study-rooms",
+ spot=art,
+ )
+ SpotExtendedInfo.objects.create(
+ key="reservation_notes",
+ value=" This space reservable "
+ "outside of TLC hours. To "
+ "reserve, go to http://www."
+ "tacoma.uw.edu/library/"
+ "reserve-group-study-rooms",
+ spot=art,
+ )
+ mgr = SpotExtendedInfo.objects.create(
+ key="manager", value="ctlt", spot=art
+ )
+ org = SpotExtendedInfo.objects.create(
+ key="organization", value="Art", spot=art
+ )
- tacoma3 = Spot.objects.create(
- name="In tacoma - #2",
- capacity=20,
- longitude=Decimal("-122.438368"),
- latitude=Decimal("47.245838"),
- building_name="West Coast Grocery " "(WCG)",
- )
- tacoma3.spottypes.add(study_room_type)
- tacoma3.save()
- tacoma_outlets = SpotExtendedInfo.objects.create(
- key="has_outlets", value="true", spot=tacoma3
- )
- tacoma_outlets = SpotExtendedInfo.objects.create(
- key="campus", value="tacoma", spot=tacoma3
- )
- mgr = SpotExtendedInfo.objects.create(
- key="manager", value="ctlt", spot=tacoma3
- )
- org = SpotExtendedInfo.objects.create(
- key="organization", value="Sociology", spot=tacoma3
- )
+ art2 = Spot.objects.create(
+ name="Also in the Art Building",
+ capacity=10,
+ longitude=Decimal("-122.306644"),
+ latitude=Decimal("47.658241"),
+ building_name="Art Building (ART)",
+ )
+ art2.spottypes.add(cafe_type)
+ art2.save()
+ art_ada = SpotExtendedInfo.objects.create(
+ key="has_whiteboards", value="true", spot=art2
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="has_outlets", value="true", spot=art2
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="has_displays", value="true", spot=art2
+ )
+ art_ada = SpotExtendedInfo.objects.create(
+ key="campus", value="seattle", spot=art2
+ )
+ mgr = SpotExtendedInfo.objects.create(
+ key="manager", value="ctlt", spot=art2
+ )
+ org = SpotExtendedInfo.objects.create(
+ key="organization", value="Art", spot=art2
+ )
- lounge_type = SpotType.objects.get_or_create(name="lounge")[0]
- fish_kitchen = Spot.objects.create(
- name="FSH 2nd Floor South Kitchen",
- longitude=Decimal("-122.31659"),
- latitude=Decimal("47.65296"),
- building_name="Fishery Sciences (FSH)",
- floor="2nd floor",
- room_number="266",
- capacity=12,
- )
- fish_kitchen.spottypes.add(lounge_type)
- fish_kitchen.save()
- fish_outlets = SpotExtendedInfo.objects.create(
- key="has_outlets", value="true", spot=fish_kitchen
- )
- fish_outlets = SpotExtendedInfo.objects.create(
- key="campus", value="seattle", spot=fish_kitchen
- )
- mgr = SpotExtendedInfo.objects.create(
- key="manager", value="ctlt", spot=fish_kitchen
- )
- org = SpotExtendedInfo.objects.create(
- key="organization", value="Fisheries", spot=fish_kitchen
- )
+ f = open(os.path.join("resources", "building3.jpg"), "rb")
- outdoor_type = SpotType.objects.get_or_create(name="outdoor")[0]
- fish_patio = Spot.objects.create(
- name="FSH 2nd Floor Patio/Deck",
- longitude=Decimal("-122.31659"),
- latitude=Decimal("47.65289"),
- building_name="Fishery Sciences " "(FSH)",
- floor="2nd floor",
- capacity=12,
- )
- fish_patio.spottypes.add(outdoor_type)
- fish_patio.save()
- fish_outlets = SpotExtendedInfo.objects.create(
- key="has_outlets", value="true", spot=fish_patio
- )
- fish_outlets = SpotExtendedInfo.objects.create(
- key="campus", value="seattle", spot=fish_patio
- )
- mgr = SpotExtendedInfo.objects.create(
- key="manager", value="ctlt", spot=fish_patio
- )
- org = SpotExtendedInfo.objects.create(
- key="organization", value="Fisheries", spot=fish_patio
- )
+ art_img1 = SpotImage.objects.create(
+ description="This is one building",
+ spot=art,
+ display_index=0,
+ image=File(f),
+ )
+ f = open(
+ os.path.join("resources", "building4.jpg"), "rb"
+ )
+ art_img2 = SpotImage.objects.create(
+ description="This is another building",
+ spot=art,
+ display_index=1,
+ image=File(f),
+ )
+ f = open(
+ os.path.join("resources", "building5.jpg"), "rb"
+ )
+ art_img3 = SpotImage.objects.create(
+ description="This is a third art building",
+ spot=art,
+ display_index=2,
+ image=File(f),
+ )
- for day in ["su", "m", "t", "w", "th", "f", "sa"]:
- SpotAvailableHours.objects.create(
- spot=lab_space,
- day=day,
- start_time="00:00",
- end_time="23:59",
- )
- SpotAvailableHours.objects.create(
- spot=art, day=day, start_time="00:00", end_time="23:59"
- )
- SpotAvailableHours.objects.create(
- spot=art2, day=day, start_time="00:00", end_time="23:59"
- )
- SpotAvailableHours.objects.create(
- spot=tacoma, day=day, start_time="00:00", end_time="23:59"
- )
- SpotAvailableHours.objects.create(
- spot=tacoma2, day=day, start_time="00:00", end_time="23:59"
- )
- SpotAvailableHours.objects.create(
- spot=tacoma3, day=day, start_time="00:00", end_time="23:59"
- )
- SpotAvailableHours.objects.create(
- spot=fish_kitchen,
- day=day,
- start_time="00:00",
- end_time="23:59",
- )
- SpotAvailableHours.objects.create(
- spot=fish_patio,
- day=day,
- start_time="00:00",
- end_time="23:59",
- )
-
- # Create rooms for Selenium testing
- # AA Balcony - like EE Patio but with different name/building
- aa_balcony = Spot.objects.create(
- name="AA Balcony",
- longitude=Decimal("-122.306371"),
- latitude=Decimal("47.653474"),
- building_name="Art Atrium",
- )
- aa_balcony.spottypes.add(outdoor_type)
- f = open(
- os.path.join(base_dir, "resources", "building3.jpg"), "rb"
+ f = open(
+ os.path.join("resources", "building6.jpg"), "rb"
+ )
+ art_img4 = SpotImage.objects.create(
+ description="This is a third art building",
+ spot=art,
+ display_index=3,
+ image=File(f),
+ )
+
+ study_room_type = SpotType.objects.get_or_create(name="study_room")[0]
+
+ tacoma = Spot.objects.create(
+ name="WCG #1",
+ capacity=20,
+ longitude=Decimal("-122.437212"),
+ latitude=Decimal("47.246213"),
+ building_name="West Coast Grocery (WCG)",
+ )
+ tacoma.spottypes.add(study_room_type)
+ tacoma.save()
+ wcg_outlets = SpotExtendedInfo.objects.create(
+ key="has_outlets", value="true", spot=tacoma
+ )
+ tacoma_outlets = SpotExtendedInfo.objects.create(
+ key="campus", value="tacoma", spot=tacoma
+ )
+ mgr = SpotExtendedInfo.objects.create(
+ key="manager", value="ctlt", spot=tacoma
+ )
+ org = SpotExtendedInfo.objects.create(
+ key="organization", value="Philosophy", spot=tacoma
+ )
+
+ tacoma2 = Spot.objects.create(
+ name="In tacoma - #2",
+ capacity=20,
+ longitude=Decimal("-122.437708"),
+ latitude=Decimal("47.244832"),
+ building_name="West Coast Grocery (WCG)",
+ )
+ tacoma2.spottypes.add(study_room_type)
+ tacoma2.save()
+ tacoma_outlets = SpotExtendedInfo.objects.create(
+ key="has_outlets", value="true", spot=tacoma2
+ )
+ mgr = SpotExtendedInfo.objects.create(
+ key="manager", value="ctlt", spot=tacoma2
+ )
+ mgr = SpotExtendedInfo.objects.create(
+ key="campus", value="tacoma", spot=tacoma2
+ )
+ org = SpotExtendedInfo.objects.create(
+ key="organization", value="Economics", spot=tacoma2
+ )
+
+ tacoma3 = Spot.objects.create(
+ name="In tacoma - #2",
+ capacity=20,
+ longitude=Decimal("-122.438368"),
+ latitude=Decimal("47.245838"),
+ building_name="West Coast Grocery (WCG)",
+ )
+ tacoma3.spottypes.add(study_room_type)
+ tacoma3.save()
+ tacoma_outlets = SpotExtendedInfo.objects.create(
+ key="has_outlets", value="true", spot=tacoma3
+ )
+ tacoma_outlets = SpotExtendedInfo.objects.create(
+ key="campus", value="tacoma", spot=tacoma3
+ )
+ mgr = SpotExtendedInfo.objects.create(
+ key="manager", value="ctlt", spot=tacoma3
+ )
+ org = SpotExtendedInfo.objects.create(
+ key="organization", value="Sociology", spot=tacoma3
+ )
+
+ lounge_type = SpotType.objects.get_or_create(name="lounge")[0]
+ fish_kitchen = Spot.objects.create(
+ name="FSH 2nd Floor South Kitchen",
+ longitude=Decimal("-122.31659"),
+ latitude=Decimal("47.65296"),
+ building_name="Fishery Sciences (FSH)",
+ floor="2nd floor",
+ room_number="266",
+ capacity=12,
+ )
+ fish_kitchen.spottypes.add(lounge_type)
+ fish_kitchen.save()
+ fish_outlets = SpotExtendedInfo.objects.create(
+ key="has_outlets", value="true", spot=fish_kitchen
+ )
+ fish_outlets = SpotExtendedInfo.objects.create(
+ key="campus", value="seattle", spot=fish_kitchen
+ )
+ mgr = SpotExtendedInfo.objects.create(
+ key="manager", value="ctlt", spot=fish_kitchen
+ )
+ org = SpotExtendedInfo.objects.create(
+ key="organization", value="Fisheries", spot=fish_kitchen
+ )
+
+ outdoor_type = SpotType.objects.get_or_create(name="outdoor")[0]
+ fish_patio = Spot.objects.create(
+ name="FSH 2nd Floor Patio/Deck",
+ longitude=Decimal("-122.31659"),
+ latitude=Decimal("47.65289"),
+ building_name="Fishery Sciences (FSH)",
+ floor="2nd floor",
+ capacity=12,
+ )
+ fish_patio.spottypes.add(outdoor_type)
+ fish_patio.save()
+ fish_outlets = SpotExtendedInfo.objects.create(
+ key="has_outlets", value="true", spot=fish_patio
+ )
+ fish_outlets = SpotExtendedInfo.objects.create(
+ key="campus", value="seattle", spot=fish_patio
+ )
+ mgr = SpotExtendedInfo.objects.create(
+ key="manager", value="ctlt", spot=fish_patio
+ )
+ org = SpotExtendedInfo.objects.create(
+ key="organization", value="Fisheries", spot=fish_patio
+ )
+
+ for day in ["su", "m", "t", "w", "th", "f", "sa"]:
+ SpotAvailableHours.objects.create(
+ spot=lab_space,
+ day=day,
+ start_time="00:00",
+ end_time="23:59",
)
- f2 = open(
- os.path.join(base_dir, "resources", "building4.jpg"), "rb"
+ SpotAvailableHours.objects.create(
+ spot=art, day=day, start_time="00:00", end_time="23:59"
)
- aa_balcony_img = SpotImage.objects.create(
- description="This is one " "building",
- spot=aa_balcony,
- display_index=0,
- image=File(f),
+ SpotAvailableHours.objects.create(
+ spot=art2, day=day, start_time="00:00", end_time="23:59"
)
- aa_balcony_img2 = SpotImage.objects.create(
- description="This is one " "building",
- spot=aa_balcony,
- display_index=1,
- image=File(f2),
+ SpotAvailableHours.objects.create(
+ spot=tacoma, day=day, start_time="00:00", end_time="23:59"
)
- aa_balcony.save()
-
- for day in ["su", "m", "t", "w", "th", "f", "sa"]:
- SpotAvailableHours.objects.create(
- spot=aa_balcony,
- day=day,
- start_time="00:00",
- end_time="23:59",
- )
-
- SpotExtendedInfo.objects.create(
- key="has_natural_light", value="true", spot=aa_balcony
+ SpotAvailableHours.objects.create(
+ spot=tacoma2, day=day, start_time="00:00", end_time="23:59"
)
- SpotExtendedInfo.objects.create(
- key="food_nearby", value="neighboring", spot=aa_balcony
+ SpotAvailableHours.objects.create(
+ spot=tacoma3, day=day, start_time="00:00", end_time="23:59"
)
- SpotExtendedInfo.objects.create(
- key="campus", value="seattle", spot=aa_balcony
+ SpotAvailableHours.objects.create(
+ spot=fish_kitchen,
+ day=day,
+ start_time="00:00",
+ end_time="23:59",
)
- SpotExtendedInfo.objects.create(
- key="location_description",
- value="Art Building Atrium",
- spot=aa_balcony,
+ SpotAvailableHours.objects.create(
+ spot=fish_patio,
+ day=day,
+ start_time="00:00",
+ end_time="23:59",
)
- # Study Room 233 - like Study Room 332 but
- # with different name/building
- study_room_233 = Spot.objects.create(
- name="Study Room 233",
- capacity=8,
- longitude=Decimal("-122.306382"),
- latitude=Decimal("47.653477"),
- building_name="Odegaard Undergraduate Library (OUGL)",
- )
- study_room_233.spottypes.add(study_room_type)
- study_room_233.save()
+ # Create rooms for Selenium testing
+ # AA Balcony - like EE Patio but with different name/building
+ aa_balcony = Spot.objects.create(
+ name="AA Balcony",
+ longitude=Decimal("-122.306371"),
+ latitude=Decimal("47.653474"),
+ building_name="Art Atrium",
+ )
+ aa_balcony.spottypes.add(outdoor_type)
+ f = open(
+ os.path.join("resources", "building3.jpg"), "rb"
+ )
+ f2 = open(
+ os.path.join("resources", "building4.jpg"), "rb"
+ )
+ aa_balcony_img = SpotImage.objects.create(
+ description="This is one " "building",
+ spot=aa_balcony,
+ display_index=0,
+ image=File(f),
+ )
+ aa_balcony_img2 = SpotImage.objects.create(
+ description="This is one " "building",
+ spot=aa_balcony,
+ display_index=1,
+ image=File(f2),
+ )
+ aa_balcony.save()
+ for day in ["su", "m", "t", "w", "th", "f", "sa"]:
SpotAvailableHours.objects.create(
- spot=study_room_233,
- day="f",
+ spot=aa_balcony,
+ day=day,
start_time="00:00",
- end_time="20:00",
- )
- SpotAvailableHours.objects.create(
- spot=study_room_233,
- day="sa",
- start_time="12:00",
- end_time="20:00",
+ end_time="23:59",
)
+
+ SpotExtendedInfo.objects.create(
+ key="has_natural_light", value="true", spot=aa_balcony
+ )
+ SpotExtendedInfo.objects.create(
+ key="food_nearby", value="neighboring", spot=aa_balcony
+ )
+ SpotExtendedInfo.objects.create(
+ key="campus", value="seattle", spot=aa_balcony
+ )
+ SpotExtendedInfo.objects.create(
+ key="location_description",
+ value="Art Building Atrium",
+ spot=aa_balcony,
+ )
+
+ # Study Room 233 - like Study Room 332 but
+ # with different name/building
+ study_room_233 = Spot.objects.create(
+ name="Study Room 233",
+ capacity=8,
+ longitude=Decimal("-122.306382"),
+ latitude=Decimal("47.653477"),
+ building_name="Odegaard Undergraduate Library (OUGL)",
+ )
+ study_room_233.spottypes.add(study_room_type)
+ study_room_233.save()
+
+ SpotAvailableHours.objects.create(
+ spot=study_room_233,
+ day="f",
+ start_time="00:00",
+ end_time="20:00",
+ )
+ SpotAvailableHours.objects.create(
+ spot=study_room_233,
+ day="sa",
+ start_time="12:00",
+ end_time="20:00",
+ )
+ SpotAvailableHours.objects.create(
+ spot=study_room_233,
+ day="su",
+ start_time="12:00",
+ end_time="23:59",
+ )
+ for day in ["m", "t", "w", "th"]:
SpotAvailableHours.objects.create(
spot=study_room_233,
- day="su",
- start_time="12:00",
+ day=day,
+ start_time="00:00",
end_time="23:59",
)
- for day in ["m", "t", "w", "th"]:
- SpotAvailableHours.objects.create(
- spot=study_room_233,
- day=day,
- start_time="00:00",
- end_time="23:59",
- )
-
- SpotExtendedInfo.objects.create(
- key="location_description",
- value="Library, 2nd floor",
- spot=study_room_233,
- )
- SpotExtendedInfo.objects.create(
- key="has_outlets", value="true", spot=study_room_233
- )
- SpotExtendedInfo.objects.create(
- key="has_printing", value="true", spot=study_room_233
- )
- SpotExtendedInfo.objects.create(
- key="has_whiteboards", value="true", spot=study_room_233
- )
- SpotExtendedInfo.objects.create(
- key="food_nearby", value="building", spot=study_room_233
- )
- SpotExtendedInfo.objects.create(
- key="reservable", value="true", spot=study_room_233
- )
- SpotExtendedInfo.objects.create(
- key="campus", value="seattle", spot=study_room_233
- )
- # Room 301 - like Room 201 but with different name/building
- room_301 = Spot.objects.create(
- name="Room 301",
- capacity=10,
- longitude=Decimal("-122.437708"),
- latitude=Decimal("47.244832"),
- building_name="Joy",
- )
- room_301.spottypes.add(study_room_type)
- room_301.save()
-
- for day in ["m", "t", "w", "th"]:
- SpotAvailableHours.objects.create(
- spot=room_301,
- day=day,
- start_time="07:00",
- end_time="22:00",
- )
-
- for day in ["f", "sa", "su"]:
- SpotAvailableHours.objects.create(
- spot=room_301,
- day=day,
- start_time="07:00",
- end_time="17:00",
- )
-
- SpotExtendedInfo.objects.create(
- key="location_description",
- value="Sad, 3rd floor",
+ SpotExtendedInfo.objects.create(
+ key="location_description",
+ value="Library, 2nd floor",
+ spot=study_room_233,
+ )
+ SpotExtendedInfo.objects.create(
+ key="has_outlets", value="true", spot=study_room_233
+ )
+ SpotExtendedInfo.objects.create(
+ key="has_printing", value="true", spot=study_room_233
+ )
+ SpotExtendedInfo.objects.create(
+ key="has_whiteboards", value="true", spot=study_room_233
+ )
+ SpotExtendedInfo.objects.create(
+ key="food_nearby", value="building", spot=study_room_233
+ )
+ SpotExtendedInfo.objects.create(
+ key="reservable", value="true", spot=study_room_233
+ )
+ SpotExtendedInfo.objects.create(
+ key="campus", value="seattle", spot=study_room_233
+ )
+
+ # Room 301 - like Room 201 but with different name/building
+ room_301 = Spot.objects.create(
+ name="Room 301",
+ capacity=10,
+ longitude=Decimal("-122.437708"),
+ latitude=Decimal("47.244832"),
+ building_name="Joy",
+ )
+ room_301.spottypes.add(study_room_type)
+ room_301.save()
+
+ for day in ["m", "t", "w", "th"]:
+ SpotAvailableHours.objects.create(
spot=room_301,
- )
- SpotExtendedInfo.objects.create(
- key="has_outlets", value="true", spot=room_301
- )
- SpotExtendedInfo.objects.create(
- key="has_natural_light", value="true", spot=room_301
- )
- SpotExtendedInfo.objects.create(
- key="food_nearby", value="building", spot=room_301
- )
- SpotExtendedInfo.objects.create(
- key="campus", value="tacoma", spot=room_301
+ day=day,
+ start_time="07:00",
+ end_time="22:00",
)
- food = Spot.objects.create(
- name="This is a food spot",
- capacity=10,
- longitude=Decimal("-122.3101087"),
- latitude=Decimal("47.6549552"),
- building_name="Food Building",
- )
- food.spottypes.add(cafe_type)
- food.save()
- food_info = SpotExtendedInfo.objects.create(
- key="app_type", value="food", spot=food
- )
- food_info = SpotExtendedInfo.objects.create(
- key="has_outlets", value="true", spot=food
+ for day in ["f", "sa", "su"]:
+ SpotAvailableHours.objects.create(
+ spot=room_301,
+ day=day,
+ start_time="07:00",
+ end_time="17:00",
)
- # get_or_create returns a tuple
- item_place_type = SpotType.objects.get_or_create(name="checkout")[
- 0
- ]
- loan_office = Spot.objects.create(
- name="Tech Loan Office",
- building_name="Kane Hall (KNE)",
- longitude=Decimal("-122.306382"),
- latitude=Decimal("47.653477"),
- )
- loan_office.spottypes.add(item_place_type)
- loan_office.save()
- SpotExtendedInfo.objects.create(
- key="app_type", value="tech", spot=loan_office
- )
- SpotExtendedInfo.objects.create(
- key="has_cte_techloan", value="true", spot=loan_office
- )
- SpotExtendedInfo.objects.create(
- key="cte_techloan_id", value="1", spot=loan_office
- )
- SpotExtendedInfo.objects.create(
- key="campus", value="seattle", spot=loan_office
- )
+ SpotExtendedInfo.objects.create(
+ key="location_description",
+ value="Sad, 3rd floor",
+ spot=room_301,
+ )
+ SpotExtendedInfo.objects.create(
+ key="has_outlets", value="true", spot=room_301
+ )
+ SpotExtendedInfo.objects.create(
+ key="has_natural_light", value="true", spot=room_301
+ )
+ SpotExtendedInfo.objects.create(
+ key="food_nearby", value="building", spot=room_301
+ )
+ SpotExtendedInfo.objects.create(
+ key="campus", value="tacoma", spot=room_301
+ )
- macbook = Item.objects.create(
- name="Apple Macbook Pro",
- spot=loan_office,
- item_category="Placeholder Category",
- item_subcategory="Laptop Computer",
- )
- f = open(
- os.path.join(base_dir, "resources", "building5.jpg"), "rb"
- )
- ItemImage.objects.create(
- item=macbook,
- image=File(f),
- display_index=0,
- description="Macbook Pro",
- )
- ItemExtendedInfo.objects.create(
- key="i_quantity", value="10", item=macbook
- )
- ItemExtendedInfo.objects.create(
- key="i_model", value="Macbook Pro", item=macbook
- )
- ItemExtendedInfo.objects.create(
- key="i_brand", value="Apple", item=macbook
- )
- ItemExtendedInfo.objects.create(
- key="i_check_out_period", value="7", item=macbook
- )
- ItemExtendedInfo.objects.create(
- key="i_is_active", value="true", item=macbook
- )
+ food = Spot.objects.create(
+ name="This is a food spot",
+ capacity=10,
+ longitude=Decimal("-122.3101087"),
+ latitude=Decimal("47.6549552"),
+ building_name="Food Building",
+ )
+ food.spottypes.add(cafe_type)
+ food.save()
+ food_info = SpotExtendedInfo.objects.create(
+ key="app_type", value="food", spot=food
+ )
+ food_info = SpotExtendedInfo.objects.create(
+ key="has_outlets", value="true", spot=food
+ )
- latitude = Item.objects.create(
- name="Dell Latitude E5440",
- spot=loan_office,
- item_category="Placeholder Category",
- item_subcategory="Laptop Computer",
- )
- ItemExtendedInfo.objects.create(
- key="i_quantity", value="12", item=latitude
- )
- ItemExtendedInfo.objects.create(
- key="i_model", value="Latitude E5440", item=latitude
- )
- ItemExtendedInfo.objects.create(
- key="i_brand", value="Dell", item=latitude
- )
- ItemExtendedInfo.objects.create(
- key="i_check_out_period", value="14", item=latitude
- )
- ItemExtendedInfo.objects.create(
- key="i_is_active", value="true", item=latitude
- )
+ # get_or_create returns a tuple
+ item_place_type = SpotType.objects.get_or_create(name="checkout")[
+ 0
+ ]
+ loan_office = Spot.objects.create(
+ name="Tech Loan Office",
+ building_name="Kane Hall (KNE)",
+ longitude=Decimal("-122.306382"),
+ latitude=Decimal("47.653477"),
+ )
+ loan_office.spottypes.add(item_place_type)
+ loan_office.save()
+ SpotExtendedInfo.objects.create(
+ key="app_type", value="tech", spot=loan_office
+ )
+ SpotExtendedInfo.objects.create(
+ key="has_cte_techloan", value="true", spot=loan_office
+ )
+ SpotExtendedInfo.objects.create(
+ key="cte_techloan_id", value="1", spot=loan_office
+ )
+ SpotExtendedInfo.objects.create(
+ key="campus", value="seattle", spot=loan_office
+ )
- passport = Item.objects.create(
- name="Fender Passport P-150",
- spot=loan_office,
- item_category="Placeholder Category",
- item_subcategory="Portable Audio System",
- )
- ItemExtendedInfo.objects.create(
- key="i_quantity", value="5", item=passport
- )
- ItemExtendedInfo.objects.create(
- key="i_model", value="Passport P-150", item=passport
- )
- ItemExtendedInfo.objects.create(
- key="i_brand", value="Fender", item=passport
- )
- ItemExtendedInfo.objects.create(
- key="i_check_out_period", value="7", item=passport
- )
- ItemExtendedInfo.objects.create(
- key="i_is_active", value="true", item=passport
- )
+ macbook = Item.objects.create(
+ name="Apple Macbook Pro",
+ spot=loan_office,
+ item_category="Placeholder Category",
+ item_subcategory="Laptop Computer",
+ )
+ f = open(
+ os.path.join("resources", "building5.jpg"), "rb"
+ )
+ ItemImage.objects.create(
+ item=macbook,
+ image=File(f),
+ display_index=0,
+ description="Macbook Pro",
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_quantity", value="10", item=macbook
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_model", value="Macbook Pro", item=macbook
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_brand", value="Apple", item=macbook
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_check_out_period", value="7", item=macbook
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_is_active", value="true", item=macbook
+ )
- other_office = Spot.objects.create(
- name="Another Loan Office",
- building_name="Kane Hall (KNE)",
- longitude=Decimal("-122.306382"),
- latitude=Decimal("47.653477"),
- )
- loan_office.spottypes.add(item_place_type)
- loan_office.save()
- SpotExtendedInfo.objects.create(
- key="app_type", value="tech", spot=other_office
- )
- SpotExtendedInfo.objects.create(
- key="has_cte_techloan", value="true", spot=other_office
- )
- SpotExtendedInfo.objects.create(
- key="cte_techloan_id", value="2", spot=other_office
- )
- SpotExtendedInfo.objects.create(
- key="campus", value="seattle", spot=other_office
- )
+ latitude = Item.objects.create(
+ name="Dell Latitude E5440",
+ spot=loan_office,
+ item_category="Placeholder Category",
+ item_subcategory="Laptop Computer",
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_quantity", value="12", item=latitude
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_model", value="Latitude E5440", item=latitude
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_brand", value="Dell", item=latitude
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_check_out_period", value="14", item=latitude
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_is_active", value="true", item=latitude
+ )
- thingy = Item.objects.create(
- name="Thingy P-150",
- spot=other_office,
- item_category="Placeholder Category",
- item_subcategory="Portable Audio System",
- )
- ItemExtendedInfo.objects.create(
- key="i_quantity", value="5", item=thingy
- )
- ItemExtendedInfo.objects.create(
- key="i_model", value="Passport P-150", item=thingy
- )
- ItemExtendedInfo.objects.create(
- key="i_brand", value="Fender", item=thingy
- )
- ItemExtendedInfo.objects.create(
- key="i_check_out_period", value="7", item=thingy
- )
- ItemExtendedInfo.objects.create(
- key="i_is_active", value="true", item=thingy
- )
+ passport = Item.objects.create(
+ name="Fender Passport P-150",
+ spot=loan_office,
+ item_category="Placeholder Category",
+ item_subcategory="Portable Audio System",
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_quantity", value="5", item=passport
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_model", value="Passport P-150", item=passport
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_brand", value="Fender", item=passport
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_check_out_period", value="7", item=passport
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_is_active", value="true", item=passport
+ )
+
+ other_office = Spot.objects.create(
+ name="Another Loan Office",
+ building_name="Kane Hall (KNE)",
+ longitude=Decimal("-122.306382"),
+ latitude=Decimal("47.653477"),
+ )
+ loan_office.spottypes.add(item_place_type)
+ loan_office.save()
+ SpotExtendedInfo.objects.create(
+ key="app_type", value="tech", spot=other_office
+ )
+ SpotExtendedInfo.objects.create(
+ key="has_cte_techloan", value="true", spot=other_office
+ )
+ SpotExtendedInfo.objects.create(
+ key="cte_techloan_id", value="2", spot=other_office
+ )
+ SpotExtendedInfo.objects.create(
+ key="campus", value="seattle", spot=other_office
+ )
+
+ thingy = Item.objects.create(
+ name="Thingy P-150",
+ spot=other_office,
+ item_category="Placeholder Category",
+ item_subcategory="Portable Audio System",
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_quantity", value="5", item=thingy
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_model", value="Passport P-150", item=thingy
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_brand", value="Fender", item=thingy
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_check_out_period", value="7", item=thingy
+ )
+ ItemExtendedInfo.objects.create(
+ key="i_is_active", value="true", item=thingy
+ )
+
+ loan_office = Spot.objects.create(
+ name="Yet Another Tech Loan Office",
+ building_name="Kane Hall (KNE)",
+ longitude=Decimal("-122.306382"),
+ latitude=Decimal("47.653477"),
+ )
+ loan_office.spottypes.add(item_place_type)
+ loan_office.save()
+ SpotExtendedInfo.objects.create(
+ key="app_type", value="tech", spot=loan_office
+ )
+ SpotExtendedInfo.objects.create(
+ key="has_cte_techloan", value="true", spot=loan_office
+ )
+ SpotExtendedInfo.objects.create(
+ key="cte_techloan_id", value="9", spot=loan_office
+ )
+ SpotExtendedInfo.objects.create(
+ key="campus", value="seattle", spot=loan_office
+ )
diff --git a/spotseeker_server/management/commands/register_application.py b/spotseeker_server/management/commands/register_application.py
new file mode 100644
index 00000000..abccbf87
--- /dev/null
+++ b/spotseeker_server/management/commands/register_application.py
@@ -0,0 +1,85 @@
+# Copyright 2024 UW-IT, University of Washington
+# SPDX-License-Identifier: Apache-2.0
+
+import logging
+from io import StringIO
+import contextlib
+
+from django.core.management.base import BaseCommand, CommandParser
+
+from spotseeker_server.models import Client
+
+from oauth2_provider.management.commands import createapplication
+from oauth2_provider.models import Application
+
+
+logger = logging.getLogger(__name__)
+
+
+class Command(BaseCommand):
+ help = "Register applications with Spotseeker."
+
+ def add_arguments(self, parser: CommandParser) -> None:
+ parser.add_argument(
+ '-s',
+ '--show-credential',
+ action='store_true',
+ default=False,
+ dest='show_credential',
+ help="Print the credential created, very sensitive info.",
+ )
+ return super().add_arguments(parser)
+
+ def handle(self, *args, **options):
+ if args and args[0]:
+ name = args[0]
+ else:
+ name = input("Enter application name: ")
+
+ logger.info("Registering application with Spotseeker...")
+
+ # check if application already exists
+ try:
+ Application.objects.get(name=name)
+ logger.info("Application already registered, skipping...")
+ return
+ except Application.DoesNotExist:
+ pass
+
+ output = StringIO()
+
+ with contextlib.redirect_stdout(output):
+ createapplication.Command().handle(
+ name=name,
+ client_type='confidential',
+ authorization_grant_type='client-credentials',
+ verbosity=0,
+ )
+
+ logger.debug("Getting client secret...")
+ secret_len = 128
+ end_char = output.tell()
+ output.seek(end_char - secret_len - 1)
+ client_secret = output.read(secret_len)
+ output.close()
+
+ logger.debug("Putting application into Client table...")
+
+ app = Application.objects.get(name=name)
+ Client.objects.create(
+ username=name,
+ name=name,
+ client_id=app.client_id,
+ client_secret=client_secret,
+ )
+
+ logger.debug("Compiling client credentials...")
+
+ client = Client.objects.get(name=name)
+ credential = client.get_client_credential()
+ client.save()
+
+ if options['show_credential']:
+ logger.info("Credential: {}".format(credential))
+
+ logger.info("Done.")
diff --git a/spotseeker_server/management/commands/retrieve_spots.py b/spotseeker_server/management/commands/retrieve_spots.py
index b364e468..78c3b08b 100644
--- a/spotseeker_server/management/commands/retrieve_spots.py
+++ b/spotseeker_server/management/commands/retrieve_spots.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.core.management.base import BaseCommand, CommandError
diff --git a/spotseeker_server/management/commands/sync_techloan.py b/spotseeker_server/management/commands/sync_techloan.py
index 7a37235c..aaf71d8c 100644
--- a/spotseeker_server/management/commands/sync_techloan.py
+++ b/spotseeker_server/management/commands/sync_techloan.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import logging
diff --git a/spotseeker_server/management/commands/techloan/spotseeker.py b/spotseeker_server/management/commands/techloan/spotseeker.py
index 65e0aff9..b45f675b 100644
--- a/spotseeker_server/management/commands/techloan/spotseeker.py
+++ b/spotseeker_server/management/commands/techloan/spotseeker.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import json
diff --git a/spotseeker_server/management/commands/techloan/techloan.py b/spotseeker_server/management/commands/techloan/techloan.py
index e86a933e..f8221c71 100644
--- a/spotseeker_server/management/commands/techloan/techloan.py
+++ b/spotseeker_server/management/commands/techloan/techloan.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import json
diff --git a/spotseeker_server/management/commands/techloan/utils.py b/spotseeker_server/management/commands/techloan/utils.py
index 27e0f341..94e33eab 100644
--- a/spotseeker_server/management/commands/techloan/utils.py
+++ b/spotseeker_server/management/commands/techloan/utils.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import re
diff --git a/spotseeker_server/middleware/persistent.py b/spotseeker_server/middleware/persistent.py
index f42b413c..228ed534 100644
--- a/spotseeker_server/middleware/persistent.py
+++ b/spotseeker_server/middleware/persistent.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
# from http://stackoverflow.com/questions/15896217/django-loading-a-page-that-
diff --git a/spotseeker_server/migrations/0001_initial.py b/spotseeker_server/migrations/0001_initial.py
index 8483e6ba..9233dda6 100644
--- a/spotseeker_server/migrations/0001_initial.py
+++ b/spotseeker_server/migrations/0001_initial.py
@@ -2,28 +2,22 @@
from __future__ import unicode_literals
from django.db import models, migrations
+import django.contrib.auth.models
+import django.contrib.auth.validators
import re
from django.conf import settings
import django.core.validators
+import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('oauth_provider', '0001_initial'),
+ ('auth', '0011_update_proxy_permissions'),
]
operations = [
- migrations.CreateModel(
- name='FavoriteSpot',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ],
- options={
- },
- bases=(models.Model,),
- ),
migrations.CreateModel(
name='Item',
fields=[
@@ -43,7 +37,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('key', models.CharField(max_length=50)),
('value', models.CharField(max_length=350)),
- ('item', models.ForeignKey(blank=True, to='spotseeker_server.Item', null=True)),
+ ('item', models.ForeignKey(blank=True, to='spotseeker_server.Item', null=True, on_delete=models.CASCADE)),
],
options={
'verbose_name_plural': 'Item extended info',
@@ -65,53 +59,7 @@ class Migration(migrations.Migration):
('etag', models.CharField(max_length=40)),
('upload_user', models.CharField(max_length=40)),
('upload_application', models.CharField(max_length=100)),
- ('item', models.ForeignKey(to='spotseeker_server.Item')),
- ],
- options={
- },
- bases=(models.Model,),
- ),
- migrations.CreateModel(
- name='SharedSpace',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('user', models.CharField(max_length=16)),
- ('sender', models.CharField(max_length=256)),
- ],
- options={
- },
- bases=(models.Model,),
- ),
- migrations.CreateModel(
- name='SharedSpaceRecipient',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('hash_key', models.CharField(max_length=32)),
- ('recipient', models.CharField(max_length=256)),
- ('user', models.CharField(default=None, max_length=16, null=True, blank=True)),
- ('date_shared', models.DateTimeField(auto_now_add=True)),
- ('shared_count', models.IntegerField()),
- ('date_first_viewed', models.DateTimeField(null=True)),
- ('viewed_count', models.IntegerField()),
- ('shared_space', models.ForeignKey(to='spotseeker_server.SharedSpace')),
- ],
- options={
- },
- bases=(models.Model,),
- ),
- migrations.CreateModel(
- name='SpaceReview',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('review', models.CharField(default=b'', max_length=1000)),
- ('original_review', models.CharField(default=b'', max_length=1000)),
- ('rating', models.IntegerField(validators=[django.core.validators.MaxValueValidator(5), django.core.validators.MinValueValidator(1)])),
- ('date_submitted', models.DateTimeField(auto_now_add=True)),
- ('date_published', models.DateTimeField(null=True)),
- ('is_published', models.BooleanField()),
- ('is_deleted', models.BooleanField()),
- ('published_by', models.ForeignKey(related_name='published_by', to=settings.AUTH_USER_MODEL, null=True)),
- ('reviewer', models.ForeignKey(related_name='reviewer', to=settings.AUTH_USER_MODEL)),
+ ('item', models.ForeignKey(to='spotseeker_server.Item', on_delete=models.CASCADE)),
],
options={
},
@@ -147,7 +95,7 @@ class Migration(migrations.Migration):
('day', models.CharField(max_length=3, choices=[(b'm', b'monday'), (b't', b'tuesday'), (b'w', b'wednesday'), (b'th', b'thursday'), (b'f', b'friday'), (b'sa', b'saturday'), (b'su', b'sunday')])),
('start_time', models.TimeField()),
('end_time', models.TimeField()),
- ('spot', models.ForeignKey(to='spotseeker_server.Spot')),
+ ('spot', models.ForeignKey(to='spotseeker_server.Spot', on_delete=models.CASCADE)),
],
options={
'verbose_name_plural': 'Spot available hours',
@@ -160,7 +108,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('key', models.CharField(max_length=50)),
('value', models.CharField(max_length=350)),
- ('spot', models.ForeignKey(to='spotseeker_server.Spot')),
+ ('spot', models.ForeignKey(to='spotseeker_server.Spot', on_delete=models.CASCADE)),
],
options={
'verbose_name_plural': 'Spot extended info',
@@ -182,7 +130,7 @@ class Migration(migrations.Migration):
('etag', models.CharField(max_length=40)),
('upload_user', models.CharField(max_length=40)),
('upload_application', models.CharField(max_length=100)),
- ('spot', models.ForeignKey(to='spotseeker_server.Spot')),
+ ('spot', models.ForeignKey(to='spotseeker_server.Spot', on_delete=models.CASCADE)),
],
options={
},
@@ -198,13 +146,40 @@ class Migration(migrations.Migration):
},
bases=(models.Model,),
),
+ migrations.CreateModel(
+ name='Client',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('password', models.CharField(max_length=128, verbose_name='password')),
+ ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
+ ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+ ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
+ ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
+ ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
+ ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
+ ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
+ ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
+ ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
+ ('name', models.CharField(max_length=255)),
+ ('client_id', models.CharField(max_length=255)),
+ ('client_secret', models.CharField(max_length=255)),
+ ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
+ ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
+ ],
+ options={
+ 'verbose_name_plural': 'OAuth Clients',
+ },
+ managers=[
+ ('objects', django.contrib.auth.models.UserManager()),
+ ],
+ ),
migrations.CreateModel(
name='TrustedOAuthClient',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('is_trusted', models.BooleanField()),
('bypasses_user_authorization', models.BooleanField()),
- ('consumer', models.ForeignKey(to='oauth_provider.Consumer')),
+ ('consumer', models.ForeignKey(to='spotseeker_server.Client', on_delete=models.CASCADE)),
],
options={
'verbose_name_plural': 'Trusted OAuth clients',
@@ -221,18 +196,6 @@ class Migration(migrations.Migration):
field=models.ManyToManyField(related_name='spots', max_length=50, null=True, to='spotseeker_server.SpotType', blank=True),
preserve_default=True,
),
- migrations.AddField(
- model_name='spacereview',
- name='space',
- field=models.ForeignKey(to='spotseeker_server.Spot'),
- preserve_default=True,
- ),
- migrations.AddField(
- model_name='sharedspace',
- name='space',
- field=models.ForeignKey(to='spotseeker_server.Spot'),
- preserve_default=True,
- ),
migrations.AlterUniqueTogether(
name='itemextendedinfo',
unique_together=set([('item', 'key')]),
@@ -240,19 +203,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='item',
name='spot',
- field=models.ForeignKey(blank=True, to='spotseeker_server.Spot', null=True),
- preserve_default=True,
- ),
- migrations.AddField(
- model_name='favoritespot',
- name='spot',
- field=models.ForeignKey(to='spotseeker_server.Spot'),
- preserve_default=True,
- ),
- migrations.AddField(
- model_name='favoritespot',
- name='user',
- field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
+ field=models.ForeignKey(blank=True, to='spotseeker_server.Spot', null=True, on_delete=models.CASCADE),
preserve_default=True,
),
]
diff --git a/spotseeker_server/migrations/0002_auto_20181029_2244.py b/spotseeker_server/migrations/0002_auto_20181029_2244.py
index 31696e5f..ecffa936 100644
--- a/spotseeker_server/migrations/0002_auto_20181029_2244.py
+++ b/spotseeker_server/migrations/0002_auto_20181029_2244.py
@@ -11,18 +11,6 @@ class Migration(migrations.Migration):
]
operations = [
- migrations.AlterField(
- model_name='spacereview',
- name='is_deleted',
- field=models.BooleanField(default=False),
- preserve_default=True,
- ),
- migrations.AlterField(
- model_name='spacereview',
- name='is_published',
- field=models.BooleanField(default=False),
- preserve_default=True,
- ),
migrations.AlterField(
model_name='trustedoauthclient',
name='bypasses_user_authorization',
diff --git a/spotseeker_server/migrations/0004_auto_20200702_1932.py b/spotseeker_server/migrations/0004_auto_20200702_1932.py
index e050326f..b37a76d8 100644
--- a/spotseeker_server/migrations/0004_auto_20200702_1932.py
+++ b/spotseeker_server/migrations/0004_auto_20200702_1932.py
@@ -17,16 +17,6 @@ class Migration(migrations.Migration):
name='image',
field=models.ImageField(upload_to='item_images'),
),
- migrations.AlterField(
- model_name='spacereview',
- name='original_review',
- field=models.CharField(default='', max_length=1000),
- ),
- migrations.AlterField(
- model_name='spacereview',
- name='review',
- field=models.CharField(default='', max_length=1000),
- ),
migrations.AlterField(
model_name='spotavailablehours',
name='day',
diff --git a/spotseeker_server/migrations/0005_auto_20230406_2328.py b/spotseeker_server/migrations/0005_auto_20230406_2328.py
new file mode 100644
index 00000000..6ba9d2d3
--- /dev/null
+++ b/spotseeker_server/migrations/0005_auto_20230406_2328.py
@@ -0,0 +1,20 @@
+# Generated by Django 2.2.28 on 2023-04-06 23:28
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('spotseeker_server', '0004_auto_20200702_1932'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='trustedoauthclient',
+ options={'verbose_name_plural': 'Trusted OAuth Clients'},
+ ),
+ migrations.DeleteModel(
+ name="Client",
+ ),
+ ]
diff --git a/spotseeker_server/migrations/0005_auto_20230407_2345.py b/spotseeker_server/migrations/0005_auto_20230407_2345.py
deleted file mode 100644
index a369b102..00000000
--- a/spotseeker_server/migrations/0005_auto_20230407_2345.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.11.29 on 2023-04-07 23:45
-from __future__ import unicode_literals
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('spotseeker_server', '0004_auto_20200702_1932'),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name='favoritespot',
- name='spot',
- ),
- migrations.RemoveField(
- model_name='favoritespot',
- name='user',
- ),
- migrations.RemoveField(
- model_name='sharedspace',
- name='space',
- ),
- migrations.RemoveField(
- model_name='sharedspacerecipient',
- name='shared_space',
- ),
- migrations.RemoveField(
- model_name='spacereview',
- name='published_by',
- ),
- migrations.RemoveField(
- model_name='spacereview',
- name='reviewer',
- ),
- migrations.RemoveField(
- model_name='spacereview',
- name='space',
- ),
- migrations.DeleteModel(
- name='FavoriteSpot',
- ),
- migrations.DeleteModel(
- name='SharedSpace',
- ),
- migrations.DeleteModel(
- name='SharedSpaceRecipient',
- ),
- migrations.DeleteModel(
- name='SpaceReview',
- ),
- ]
diff --git a/spotseeker_server/migrations/0006_auto_20230420_2214.py b/spotseeker_server/migrations/0006_auto_20230420_2214.py
new file mode 100644
index 00000000..36d6160d
--- /dev/null
+++ b/spotseeker_server/migrations/0006_auto_20230420_2214.py
@@ -0,0 +1,50 @@
+from django.db import migrations, models
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('auth', '0011_update_proxy_permissions'),
+ ('spotseeker_server', '0005_auto_20230406_2328'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Client',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('password', models.CharField(max_length=128, verbose_name='password')),
+ ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
+ ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+ ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
+ ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
+ ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
+ ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
+ ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
+ ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
+ ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
+ ('name', models.CharField(max_length=255)),
+ ('client_id', models.CharField(max_length=255)),
+ ('client_secret', models.CharField(max_length=255)),
+ ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
+ ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
+ ],
+ options={
+ 'verbose_name_plural': 'OAuth Clients',
+ },
+ managers=[
+ ('objects', django.contrib.auth.models.UserManager()),
+ ],
+ ),
+ migrations.AddField(
+ model_name='client',
+ name='access_token',
+ field=models.CharField(blank=True, max_length=255),
+ ),
+ migrations.AddField(
+ model_name='client',
+ name='client_credential',
+ field=models.CharField(blank=True, max_length=255),
+ ),
+ ]
diff --git a/spotseeker_server/migrations/0007_remove_client_access_token.py b/spotseeker_server/migrations/0007_remove_client_access_token.py
new file mode 100644
index 00000000..2139c1d2
--- /dev/null
+++ b/spotseeker_server/migrations/0007_remove_client_access_token.py
@@ -0,0 +1,17 @@
+# Generated by Django 2.2.28 on 2023-05-05 15:03
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('spotseeker_server', '0006_auto_20230420_2214'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='client',
+ name='access_token',
+ ),
+ ]
diff --git a/spotseeker_server/migrations/0008_delete_trustedoauthclient.py b/spotseeker_server/migrations/0008_delete_trustedoauthclient.py
new file mode 100644
index 00000000..75d626c0
--- /dev/null
+++ b/spotseeker_server/migrations/0008_delete_trustedoauthclient.py
@@ -0,0 +1,16 @@
+# Generated by Django 2.2.28 on 2023-06-29 22:52
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('spotseeker_server', '0007_remove_client_access_token'),
+ ]
+
+ operations = [
+ migrations.DeleteModel(
+ name='TrustedOAuthClient',
+ ),
+ ]
diff --git a/spotseeker_server/models/__init__.py b/spotseeker_server/models/__init__.py
index c5bc911f..6877a53a 100644
--- a/spotseeker_server/models/__init__.py
+++ b/spotseeker_server/models/__init__.py
@@ -1,7 +1,7 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
-from .auth import TrustedOAuthClient
+from .auth import Client
from .item import Item, ItemExtendedInfo, ItemImage
from .spot import Spot, SpotAvailableHours, SpotExtendedInfo, \
SpotImage, SpotType
diff --git a/spotseeker_server/models/auth.py b/spotseeker_server/models/auth.py
index 6b4afb29..b329f02c 100644
--- a/spotseeker_server/models/auth.py
+++ b/spotseeker_server/models/auth.py
@@ -1,21 +1,31 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.db import models
+from django.contrib.auth.models import AbstractUser
-import oauth_provider.models
+from base64 import b64encode
-class TrustedOAuthClient(models.Model):
- consumer = models.ForeignKey(oauth_provider.models.Consumer)
- is_trusted = models.BooleanField(default=False)
- bypasses_user_authorization = models.BooleanField(default=False)
+class Client(AbstractUser):
+ name = models.CharField(max_length=255)
+ client_id = models.CharField(max_length=255)
+ client_secret = models.CharField(max_length=255)
+ client_credential = models.CharField(max_length=255, blank=True)
class Meta:
- verbose_name_plural = "Trusted OAuth clients"
+ verbose_name_plural = "OAuth Clients"
- def __unicode__(self):
- return self.consumer.name
+ def get_client_credential(self) -> str:
+ """
+ creates a client credential for the client, setting it for the Client
+ and returning it
+ """
+
+ raw_cred = f"{self.client_id}:{self.client_secret}"
+ self.client_credential = b64encode(raw_cred.encode('utf-8'))\
+ .decode('utf-8')
+ return self.client_credential
def __str__(self):
- return self.__unicode__()
+ return self.name
diff --git a/spotseeker_server/models/item.py b/spotseeker_server/models/item.py
index 558ac3bc..b4b85cd1 100644
--- a/spotseeker_server/models/item.py
+++ b/spotseeker_server/models/item.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from PIL import Image
@@ -15,7 +15,8 @@
class Item(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, blank=True)
- spot = models.ForeignKey(Spot, blank=True, null=True)
+ spot = models.ForeignKey(Spot, blank=True, null=True,
+ on_delete=models.CASCADE)
# These need to be item_ cat/subcat due to DB issues
item_category = models.CharField(max_length=50, null=True)
item_subcategory = models.CharField(max_length=50, null=True)
@@ -50,7 +51,8 @@ def json_data_structure(self):
class ItemExtendedInfo(models.Model):
- item = models.ForeignKey(Item, blank=True, null=True)
+ item = models.ForeignKey(Item, blank=True, null=True,
+ on_delete=models.CASCADE)
key = models.CharField(max_length=50)
value = models.CharField(max_length=350)
@@ -81,7 +83,7 @@ class ItemImage(models.Model):
description = models.CharField(max_length=200, blank=True)
display_index = models.PositiveIntegerField(null=True, blank=True)
image = models.ImageField(upload_to="item_images")
- item = models.ForeignKey(Item)
+ item = models.ForeignKey(Item, on_delete=models.CASCADE)
content_type = models.CharField(max_length=40)
width = models.IntegerField()
height = models.IntegerField()
diff --git a/spotseeker_server/models/spot.py b/spotseeker_server/models/spot.py
index 83af0d3f..6c6e8156 100644
--- a/spotseeker_server/models/spot.py
+++ b/spotseeker_server/models/spot.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -14,13 +14,11 @@
from PIL import Image
-from django.contrib.auth.models import User
from django.core.cache import cache
from django.core.files.uploadedfile import UploadedFile
from django.core.exceptions import ValidationError
from django.core.validators import validate_slug
from django.db import models
-from django.db.models import Sum, Count
from django.urls import reverse
from .utility import update_etag
@@ -188,7 +186,7 @@ class SpotAvailableHours(models.Model):
("su", "sunday"),
)
- spot = models.ForeignKey(Spot)
+ spot = models.ForeignKey(Spot, on_delete=models.CASCADE)
day = models.CharField(max_length=3, choices=DAY_CHOICES)
start_time = models.TimeField()
@@ -244,7 +242,7 @@ class SpotExtendedInfo(models.Model):
key = models.CharField(max_length=50)
value = models.CharField(max_length=350)
- spot = models.ForeignKey(Spot)
+ spot = models.ForeignKey(Spot, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "Spot extended info"
@@ -277,7 +275,7 @@ class SpotImage(models.Model):
description = models.CharField(max_length=200, blank=True)
display_index = models.PositiveIntegerField(null=True, blank=True)
image = models.ImageField(upload_to="space_images")
- spot = models.ForeignKey(Spot)
+ spot = models.ForeignKey(Spot, on_delete=models.CASCADE)
content_type = models.CharField(max_length=40)
width = models.IntegerField()
height = models.IntegerField()
diff --git a/spotseeker_server/models/utility.py b/spotseeker_server/models/utility.py
index d767d3b3..32b9b639 100644
--- a/spotseeker_server/models/utility.py
+++ b/spotseeker_server/models/utility.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from functools import wraps
diff --git a/spotseeker_server/org_filters/uw_search.py b/spotseeker_server/org_filters/uw_search.py
index 9b5dc368..0ac229fd 100644
--- a/spotseeker_server/org_filters/uw_search.py
+++ b/spotseeker_server/org_filters/uw_search.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
diff --git a/spotseeker_server/org_forms/uiuc_spot.py b/spotseeker_server/org_forms/uiuc_spot.py
index 6c0993a2..9f8397ca 100644
--- a/spotseeker_server/org_forms/uiuc_spot.py
+++ b/spotseeker_server/org_forms/uiuc_spot.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
diff --git a/spotseeker_server/org_forms/uw_spot.py b/spotseeker_server/org_forms/uw_spot.py
index 32906509..d007de36 100644
--- a/spotseeker_server/org_forms/uw_spot.py
+++ b/spotseeker_server/org_forms/uw_spot.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -11,9 +11,7 @@
from django.dispatch import receiver
from spotseeker_server.default_forms.spot import DefaultSpotForm
from spotseeker_server.default_forms.spot import DefaultSpotExtendedInfoForm
-from spotseeker_server.models import Spot, SpotExtendedInfo
from spotseeker_server.dispatch import spot_post_build
-import simplejson as json
import re
import phonenumbers
@@ -21,7 +19,7 @@
# dict of all of the uw extended info with values that must be validated
# and what all of the possible validated values are, or validated types
validated_ei = {
- "app_type": ["food", "tech"],
+ "app_type": ["food", "study", "tech"],
"auto_labstats_available": "int",
"auto_labstats_total": "int",
"campus": ["seattle", "tacoma", "bothell", "south_lake_union"],
diff --git a/spotseeker_server/require_auth.py b/spotseeker_server/require_auth.py
deleted file mode 100644
index cad47225..00000000
--- a/spotseeker_server/require_auth.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# Copyright 2023 UW-IT, University of Washington
-# SPDX-License-Identifier: Apache-2.0
-
-""" Changes
- =================================================================
-
- sbutler1@illinois.edu: only load the auth modules once on app
- initialization.
- ^ This is being reverted back to being loaded every time. After
- profiling, it didn't seem like there was hardly any speed
- difference, and only loading this once on application load
- breaks our unit tests.
-"""
-
-from django.http import HttpResponse
-from django.core.exceptions import ImproperlyConfigured
-import spotseeker_server.auth.all_ok
-from spotseeker_server.load_module import load_module_by_name
-
-from functools import wraps
-
-from django.conf import settings
-
-
-def get_auth_module():
- try:
- mod_name = settings.SPOTSEEKER_AUTH_MODULE
- except (NameError, AttributeError):
- return spotseeker_server.auth.all_ok
- return load_module_by_name(mod_name)
-
-
-def get_auth_method(method_name):
- mod = get_auth_module()
- try:
- return getattr(mod, method_name)
- except (AttributeError, NameError):
- raise ImproperlyConfigured(
- 'Module "%s" does not define a "%s" '
- "method." % (mod, method_name)
- )
-
-
-def check_auth(method_name, func, *args, **kwargs):
- method = get_auth_method(method_name)
- bad_response = method(*args, **kwargs)
- if bad_response:
- return bad_response
- else:
- return func(*args, **kwargs)
-
-
-def app_auth_required(func):
- @wraps(func)
- def _checkAuth(*args, **kwargs):
- return check_auth("authenticate_application", func, *args, **kwargs)
-
- return _checkAuth
-
-
-def user_auth_required(func):
- @wraps(func)
- def _checkAuth(*args, **kwargs):
- return check_auth("authenticate_user", func, *args, **kwargs)
-
- return _checkAuth
-
-
-def admin_auth_required(func):
- @wraps(func)
- def _checkAuth(*args, **kwargs):
- ###
- # XXX - this needs to change to something else. stop-gap measure
- ###
- bad_response = HttpResponse("Error - admin access required")
- bad_response.status_code = 401
-
- if not hasattr(settings, "SPOTSEEKER_AUTH_ADMINS"):
- print("Set SPOTSEEKER_AUTH_ADMINS in your settings.py")
- return bad_response
-
- admins = settings.SPOTSEEKER_AUTH_ADMINS
- if not isinstance(admins, (list, tuple)):
- print("SPOTSEEKER_AUTH_ADMINS must be a list or tuple")
- return bad_response
-
- request = args[1]
- username = request.META["SS_OAUTH_USER"]
- if username not in admins:
- return bad_response
-
- return func(*args, **kwargs)
-
- return _checkAuth
diff --git a/spotseeker_server/templates/registration/login.html b/spotseeker_server/templates/registration/login.html
new file mode 100644
index 00000000..99da5323
--- /dev/null
+++ b/spotseeker_server/templates/registration/login.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/spotseeker_server/test/__init__.py b/spotseeker_server/test/__init__.py
index bae5c3f5..70438815 100644
--- a/spotseeker_server/test/__init__.py
+++ b/spotseeker_server/test/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
diff --git a/spotseeker_server/test/auth/__init__.py b/spotseeker_server/test/auth/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/spotseeker_server/test/auth/all_ok.py b/spotseeker_server/test/auth/all_ok.py
deleted file mode 100644
index 7da248bd..00000000
--- a/spotseeker_server/test/auth/all_ok.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright 2023 UW-IT, University of Washington
-# SPDX-License-Identifier: Apache-2.0
-
-from django.test import TestCase
-from django.conf import settings
-from spotseeker_server.models import Spot
-import simplejson as json
-from django.test.utils import override_settings
-
-
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
-class SpotAuthAllOK(TestCase):
- """Tests that the all_ok auth module
- successfully allows any client access.
- """
-
- def setUp(self):
- spot = Spot.objects.create(
- name="This is for testing the all ok auth module", capacity=10
- )
- self.spot = spot
- self.url = "/api/v1/spot/%s" % self.spot.pk
-
- def test_get(self):
- c = self.client
- response = c.get(self.url)
- spot_dict = json.loads(response.content)
- returned_spot = Spot.objects.get(pk=spot_dict["id"])
- self.assertEquals(returned_spot, self.spot, "Returns the correct spot")
-
- @override_settings(
- SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms."
- "spot.DefaultSpotForm",
- SPOTSEEKER_SPOTEXTENDEDINFO_FORM="spotseeker_server.default_forms."
- "spot.DefaultSpotExtendedInfoForm",
- SPOTSEEKER_AUTH_ADMINS=("demo_user",),
- )
- def test_put(self):
- c = self.client
- response = c.get(self.url)
- etag = response["ETag"]
-
- spot_dict = json.loads(response.content)
- spot_dict["location"] = {"latitude": 55, "longitude": -30}
- spot_dict["name"] = "Modifying all ok"
-
- response = c.put(
- self.url,
- json.dumps(spot_dict),
- content_type="application/json",
- If_Match=etag,
- )
- self.assertEquals(
- response.status_code, 200, "Accepts a valid json string"
- )
-
- updated_spot = Spot.objects.get(pk=self.spot.pk)
- self.assertEquals(
- updated_spot.name,
- "Modifying all ok",
- "a valid PUT changes the name",
- )
diff --git a/spotseeker_server/test/auth/oauth.py b/spotseeker_server/test/auth/oauth.py
deleted file mode 100644
index 2d946853..00000000
--- a/spotseeker_server/test/auth/oauth.py
+++ /dev/null
@@ -1,362 +0,0 @@
-# Copyright 2023 UW-IT, University of Washington
-# SPDX-License-Identifier: Apache-2.0
-
-from django.test import TestCase
-from django.conf import settings
-from django.core.management import call_command
-from spotseeker_server.models import Spot, TrustedOAuthClient
-import simplejson as json
-import hashlib
-import time
-import random
-from oauth_provider.models import Consumer
-from oauthlib import oauth1
-from django.test.utils import override_settings
-from unittest.mock import patch, MagicMock
-from spotseeker_server import models
-from spotseeker_server.require_auth import get_auth_module, get_auth_method
-from spotseeker_server.auth import all_ok, oauth, fake_oauth
-from django.core.exceptions import ImproperlyConfigured
-
-
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.oauth")
-class SpotAuthOAuth(TestCase):
- def setUp(self):
- spot = Spot.objects.create(
- name="This is for testing the oauth module", capacity=10
- )
- self.spot = spot
- self.url = "/api/v1/spot/%s" % self.spot.pk
-
- def test_get_no_oauth(self):
- c = self.client
- response = c.get(self.url)
- self.assertEquals(
- response.status_code, 401, "No access to GET w/o oauth"
- )
-
- def test_valid_oauth(self):
- consumer_name = "Test consumer"
-
- key = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
- secret = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
-
- create_consumer = Consumer.objects.create(
- name=consumer_name, key=key, secret=secret
- )
-
- client = oauth1.Client(key, client_secret=secret)
- _, headers, _ = client.sign("http://testserver" + self.url)
-
- c = self.client
- response = c.get(self.url, HTTP_AUTHORIZATION=headers["Authorization"])
-
- self.assertEquals(
- response.status_code,
- 200,
- "Got a 200 w/ a proper oauth client connection",
- )
-
- spot_dict = json.loads(response.content)
-
- self.assertEquals(
- spot_dict["id"], self.spot.pk, "Got the right spot back from oauth"
- )
-
- def test_invalid_oauth(self):
- client = oauth1.Client(
- "This is a fake key", client_secret="This is a fake secret"
- )
- _, headers, _ = client.sign("http://testserver" + self.url)
-
- c = self.client
- response = c.get(self.url, HTTP_AUTHORIZATION=headers["Authorization"])
-
- self.assertEquals(
- response.status_code,
- 401,
- "Got a 401 w/ an invented oauth client id",
- )
-
- @override_settings(
- SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.sp"
- "ot.DefaultSpotForm"
- )
- @override_settings(
- SPOTSEEKER_SPOTEXTENDEDINFO_FORM="spotseeker_server.default_forms.sp"
- "ot.DefaultSpotExtendedInfoForm"
- )
- def test_put_no_oauth(self):
- c = self.client
-
- response = c.get(self.url)
-
- etag = self.spot.etag
-
- spot_dict = self.spot.json_data_structure()
- spot_dict["name"] = "Failing to modify oauth"
-
- response = c.put(
- self.url,
- json.dumps(spot_dict),
- content_type="application/json",
- If_Match=etag,
- )
- self.assertEquals(
- response.status_code, 401, "Rejects a PUT w/o oauth info"
- )
-
- @override_settings(
- SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.sp"
- "ot.DefaultSpotForm"
- )
- @override_settings(
- SPOTSEEKER_SPOTEXTENDEDINFO_FORM="spotseeker_server.default_forms.sp"
- "ot.DefaultSpotExtendedInfoForm"
- )
- def test_put_untrusted_oauth(self):
- consumer_name = "Untrusted test consumer"
-
- key = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
- secret = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
-
- create_consumer = Consumer.objects.create(
- name=consumer_name, key=key, secret=secret
- )
-
- client = oauth1.Client(key, client_secret=secret)
- _, headers, _ = client.sign("http://testserver" + self.url)
-
- c = self.client
- response = c.get(self.url, HTTP_AUTHORIZATION=headers["Authorization"])
- etag = response["ETag"]
-
- spot_dict = json.loads(response.content)
- spot_dict["name"] = "Failing to modify oauth"
- spot_dict["location"] = {"latitude": 55, "longitude": -30}
-
- response = c.put(
- self.url,
- json.dumps(spot_dict),
- content_type="application/json",
- If_Match=etag,
- HTTP_AUTHORIZATION=headers["Authorization"],
- )
- self.assertEquals(
- response.status_code,
- 401,
- "Rejects a PUT from a non-trusted oauth client",
- )
-
- @override_settings(
- SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.sp"
- "ot.DefaultSpotForm"
- )
- @override_settings(
- SPOTSEEKER_SPOTEXTENDEDINFO_FORM="spotseeker_server.default_forms.sp"
- "ot.DefaultSpotExtendedInfoForm"
- )
- def test_put_untrusted_oauth_with_user_header(self):
- consumer_name = "Untrusted test consumer"
-
- key = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
- secret = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
-
- create_consumer = Consumer.objects.create(
- name=consumer_name, key=key, secret=secret
- )
-
- client = oauth1.Client(key, client_secret=secret)
- _, headers, _ = client.sign("http://testserver" + self.url)
-
- c = self.client
- response = c.get(self.url, HTTP_AUTHORIZATION=headers["Authorization"])
- etag = response["ETag"]
-
- spot_dict = json.loads(response.content)
- spot_dict["name"] = "Failing to modify oauth"
-
- response = c.put(
- self.url,
- json.dumps(spot_dict),
- content_type="application/json",
- If_Match=etag,
- HTTP_AUTHORIZATION=headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- self.assertEquals(
- response.status_code,
- 401,
- "Rejects a PUT from a non-trusted oauth client",
- )
-
- @override_settings(
- SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.sp"
- "ot.DefaultSpotForm"
- )
- @override_settings(
- SPOTSEEKER_SPOTEXTENDEDINFO_FORM="spotseeker_server.default_forms.sp"
- "ot.DefaultSpotExtendedInfoForm"
- )
- @override_settings(SPOTSEEKER_AUTH_ADMINS=("pmichaud",))
- def test_put_trusted_client(self):
- consumer_name = "Trusted test consumer"
-
- key = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
- secret = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
-
- create_consumer = Consumer.objects.create(
- name=consumer_name, key=key, secret=secret
- )
- trusted_consumer = TrustedOAuthClient.objects.create(
- consumer=create_consumer,
- is_trusted=True,
- bypasses_user_authorization=False,
- )
-
- client = oauth1.Client(key, client_secret=secret)
- _, headers, _ = client.sign("http://testserver" + self.url)
-
- c = self.client
- response = c.get(self.url, HTTP_AUTHORIZATION=headers["Authorization"])
- etag = response["ETag"]
-
- spot_dict = json.loads(response.content)
- spot_dict["name"] = "Failing to modify oauth"
- spot_dict["location"] = {"latitude": 55, "longitude": -30}
-
- response = c.put(
- self.url,
- json.dumps(spot_dict),
- content_type="application/json",
- If_Match=etag,
- HTTP_AUTHORIZATION=headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- self.assertEquals(
- response.status_code,
- 200,
- "Accepts a PUT from a trusted oauth client",
- )
-
- @override_settings(
- SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.sp"
- "ot.DefaultSpotForm"
- )
- @override_settings(
- SPOTSEEKER_SPOTEXTENDEDINFO_FORM="spotseeker_server.default_forms.sp"
- "ot.DefaultSpotExtendedInfoForm"
- )
- def test_put_trusted_client_no_user(self):
- consumer_name = "Trusted test consumer"
-
- key = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
- secret = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
-
- create_consumer = Consumer.objects.create(
- name=consumer_name, key=key, secret=secret
- )
- trusted_consumer = TrustedOAuthClient.objects.create(
- consumer=create_consumer,
- is_trusted=True,
- bypasses_user_authorization=False,
- )
-
- client = oauth1.Client(key, client_secret=secret)
- _, headers, _ = client.sign("http://testserver" + self.url)
-
- c = self.client
- response = c.get(self.url, HTTP_AUTHORIZATION=headers["Authorization"])
- etag = response["ETag"]
-
- spot_dict = json.loads(response.content)
- spot_dict["name"] = "Failing to modify oauth"
-
- response = c.put(
- self.url,
- json.dumps(spot_dict),
- content_type="application/json",
- If_Match=etag,
- HTTP_AUTHORIZATION=headers["Authorization"],
- )
- self.assertEquals(
- response.status_code,
- 401,
- "Rejects a PUT from a trusted oauth client w/o a given user",
- )
-
- def test_create_trusted_client(self):
- """Tests to be sure the create_consumer
- command can create trusted clients.
- """
- consumer_name = "This is for testing create_consumer"
-
- call_command(
- "create_consumer",
- consumer_name=consumer_name,
- trusted="yes",
- silent=True,
- )
-
- consumer = Consumer.objects.get(name=consumer_name)
-
- client = TrustedOAuthClient.objects.get(consumer=consumer)
-
- self.assertIsInstance(client, TrustedOAuthClient)
-
- @override_settings()
- def test_get_auth_module(self):
- del settings.SPOTSEEKER_AUTH_MODULE
- self.assertEqual(all_ok, get_auth_module())
-
- with override_settings(SPOTSEEKER_AUTH_MODULE=''
- 'spotseeker_server.auth.all_ok'):
- self.assertEqual(all_ok, get_auth_module())
-
- with override_settings(SPOTSEEKER_AUTH_MODULE=''
- 'spotseeker_server.auth.oauth'):
- self.assertEqual(oauth, get_auth_module())
-
- with override_settings(SPOTSEEKER_AUTH_MODULE=''
- 'spotseeker_server.auth.fake_oauth'):
- self.assertEqual(fake_oauth, get_auth_module())
-
- @override_settings()
- def test_get_auth_method(self):
- with override_settings(SPOTSEEKER_AUTH_MODULE=''
- 'spotseeker_server.auth.all_ok'):
- self.assertEqual(None,
- get_auth_method('authenticate_application')())
-
- with override_settings(SPOTSEEKER_AUTH_MODULE=''
- 'spotseeker_server.auth.fake_oauth'):
- self.assertEqual(None,
- get_auth_method('authenticate_application')())
-
- with override_settings(SPOTSEEKER_AUTH_MODULE=''
- 'spotseeker_server.auth.oauth'):
- auth_method = get_auth_method('authenticate_application')
- response = auth_method('bad arg0', 'bad arg1')
- self.assertEqual(401, response.status_code)
-
- self.assertRaises(ImproperlyConfigured, get_auth_method, 'fake')
diff --git a/spotseeker_server/test/auth/oauth_logger.py b/spotseeker_server/test/auth/oauth_logger.py
deleted file mode 100644
index 60af9a40..00000000
--- a/spotseeker_server/test/auth/oauth_logger.py
+++ /dev/null
@@ -1,278 +0,0 @@
-# Copyright 2023 UW-IT, University of Washington
-# SPDX-License-Identifier: Apache-2.0
-
-try:
- from StringIO import StringIO
-except ModuleNotFoundError:
- from io import StringIO
-
-from django.test import TestCase
-from django.conf import settings
-from spotseeker_server.models import Spot, TrustedOAuthClient
-from django.test.client import Client
-import re
-import simplejson as json
-import logging
-
-import hashlib
-import time
-import random
-
-from oauth_provider.models import Consumer
-from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
-
-from oauthlib import oauth1
-
-
-@override_settings(
- SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms."
- "spot.DefaultSpotForm",
- SPOTSEEKER_SPOTEXTENDEDINFO_FORM="spotseeker_server.default_forms."
- "spot.DefaultSpotExtendedInfoForm",
- SPOTSEEKER_AUTH_ADMINS=("pmichaud",),
-)
-class SpotAuthOAuthLogger(TestCase):
- @classmethod
- def setUpTestData(self):
- spot = Spot.objects.create(
- name="This is for testing the oauth module", capacity=10
- )
- self.spot = spot
- self.url = "/api/v1/spot/%s" % self.spot.pk
-
- def setUp(self):
- new_middleware = []
- has_logger = False
- self.original_middleware = settings.MIDDLEWARE
- for middleware in settings.MIDDLEWARE:
- new_middleware.append(middleware)
- if middleware == "spotseeker_server.logger.oauth.LogMiddleware":
- has_logger = True
-
- if not has_logger:
- new_middleware.append(
- "spotseeker_server.logger.oauth.LogMiddleware"
- )
- settings.MIDDLEWARE = new_middleware
-
- self.stream = StringIO()
- self.handler = logging.StreamHandler(self.stream)
- self.log = logging.getLogger("spotseeker_server.logger.oauth")
- self.log.setLevel(logging.INFO)
- for handler in self.log.handlers:
- self.log.removeHandler(handler)
- self.log.addHandler(self.handler)
-
- def test_log_value_2_legged(self):
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.oauth"
- ):
-
- consumer_name = "Test consumer"
-
- key = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode(
- "utf-8"
- )
- ).hexdigest()
- secret = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode(
- "utf-8"
- )
- ).hexdigest()
-
- create_consumer = Consumer.objects.create(
- name=consumer_name, key=key, secret=secret
- )
-
- client = oauth1.Client(key, client_secret=secret)
- _, headers, _ = client.sign(
- "http://testserver/api/v1/spot/%s" % self.spot.pk
- )
-
- response = Client().get(
- self.url, HTTP_AUTHORIZATION=headers["Authorization"]
- )
-
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
-
- self.handler.flush()
- log_message = self.stream.getvalue()
-
- matches = re.search(
- r'\[.*?\] ([\d]+)\t"(.*?)"\t-\t"GET /api'
- r'/v1/spot/([\d]+)" ([\d]+) ([\d]+)',
- log_message,
- )
-
- consumer_id = int(matches.group(1))
- consumer_name = matches.group(2)
- spot_id = int(matches.group(3))
- status_code = int(matches.group(4))
- response_size = int(matches.group(5))
-
- self.assertEquals(
- consumer_id, create_consumer.pk, "Logging correct consumer PK"
- )
- self.assertEquals(
- consumer_name,
- create_consumer.name,
- "Logging correct consumer name",
- )
- self.assertEquals(spot_id, self.spot.pk, "Logging correct uri")
- self.assertEquals(
- status_code,
- response.status_code,
- "Logging correct status_code",
- )
- self.assertEquals(
- response_size,
- len(response.content.decode()),
- "Logging correct content size",
- )
-
- def test_log_trusted_3_legged(self):
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.oauth"
- ):
- consumer_name = "Trusted test consumer"
-
- key = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode(
- "utf-8"
- )
- ).hexdigest()
- secret = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode(
- "utf-8"
- )
- ).hexdigest()
-
- create_consumer = Consumer.objects.create(
- name=consumer_name, key=key, secret=secret
- )
- trusted_consumer = TrustedOAuthClient.objects.create(
- consumer=create_consumer,
- is_trusted=True,
- bypasses_user_authorization=False,
- )
-
- client = oauth1.Client(key, client_secret=secret)
- _, headers, _ = client.sign(
- "http://testserver/api/v1/spot/%s" % self.spot.pk
- )
-
- c = Client()
- response = c.get(
- self.url, HTTP_AUTHORIZATION=headers["Authorization"]
- )
- etag = response["ETag"]
-
- spot_dict = json.loads(response.content)
- spot_dict["name"] = "Failing to modify oauth"
- spot_dict["location"] = {"latitude": 55, "longitude": -30}
-
- response = c.put(
- self.url,
- json.dumps(spot_dict),
- content_type="application/json",
- If_Match=etag,
- HTTP_AUTHORIZATION=headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- self.assertEquals(
- response.status_code,
- 200,
- "Accespts a PUT from a trusted oauth client",
- )
-
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
-
- self.handler.flush()
- log_message = self.stream.getvalue()
-
- matches = re.search(
- r'\n\[.*?\] ([\d]+)\t"(.*?)"\t(.*?)\t"PUT /api/v1/spo'
- r't/([\d]+)" ([\d]+) ([\d]+)',
- log_message,
- re.MULTILINE,
- )
-
- consumer_id = int(matches.group(1))
- consumer_name = matches.group(2)
- user_name = matches.group(3)
- spot_id = int(matches.group(4))
- status_code = int(matches.group(5))
- response_size = int(matches.group(6))
-
- self.assertEquals(
- consumer_id, create_consumer.pk, "Logging correct consumer PK"
- )
- self.assertEquals(
- consumer_name,
- create_consumer.name,
- "Logging correct consumer name",
- )
- self.assertEquals(
- user_name, "pmichaud", "Logging correct oauth username"
- )
- self.assertEquals(spot_id, self.spot.pk, "Logging correct uri")
- self.assertEquals(
- status_code,
- response.status_code,
- "Logging correct status_code",
- )
- self.assertEquals(
- response_size,
- len(response.content.decode()),
- "Logging correct content size",
- )
-
- def test_invalid(self):
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.oauth"
- ):
-
- c = Client()
- response = c.get(self.url)
-
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
-
- self.handler.flush()
- log_message = self.stream.getvalue()
-
- matches = re.search(
- r'\[.*?\] -\t"-"\t-\t"GET /api/v1/spot'
- r'/([\d]+)" ([\d]+) ([\d]+)',
- log_message,
- )
-
- spot_id = int(matches.group(1))
- status_code = int(matches.group(2))
- response_size = int(matches.group(3))
-
- self.assertEquals(spot_id, self.spot.pk, "Logging correct uri")
- self.assertEquals(
- status_code,
- response.status_code,
- "Logging correct status_code",
- )
- self.assertEquals(
- response_size,
- len(response.content),
- "Logging correct content size",
- )
-
- def tearDown(self):
- self.log.removeHandler(self.handler)
- self.handler.close()
-
- settings.MIDDLEWARE = self.original_middleware
diff --git a/spotseeker_server/test/buildings.py b/spotseeker_server/test/buildings.py
index ec3c33a5..592262fd 100644
--- a/spotseeker_server/test/buildings.py
+++ b/spotseeker_server/test/buildings.py
@@ -1,18 +1,15 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
-from spotseeker_server.models import Spot, SpotExtendedInfo
-from spotseeker_server import models
-from mock import patch
+from spotseeker_server.models import Spot
from django.test.utils import override_settings
import simplejson as json
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms."
"spot.DefaultSpotForm",
)
diff --git a/spotseeker_server/test/hours/get.py b/spotseeker_server/test/hours/get.py
index 54a743c9..31242dab 100644
--- a/spotseeker_server/test/hours/get.py
+++ b/spotseeker_server/test/hours/get.py
@@ -1,17 +1,14 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
from spotseeker_server.models import Spot, SpotAvailableHours
import simplejson as json
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotHoursGETTest(TestCase):
def setUp(self):
spot = Spot.objects.create(name="This spot has available hours")
diff --git a/spotseeker_server/test/hours/hours_range.py b/spotseeker_server/test/hours/hours_range.py
index 7d7b4988..a93a1463 100644
--- a/spotseeker_server/test/hours/hours_range.py
+++ b/spotseeker_server/test/hours/hours_range.py
@@ -1,17 +1,15 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from datetime import datetime, timedelta
from django.test import TestCase
from django.test.client import Client
from django.test.utils import override_settings
-from mock import patch
from spotseeker_server import models
import json
-import time
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class HoursRangeTest(TestCase):
"""Tests searches for spots that are open anywhere
within a range of hours.
diff --git a/spotseeker_server/test/hours/model.py b/spotseeker_server/test/hours/model.py
index 40ccc4ee..72ffb518 100644
--- a/spotseeker_server/test/hours/model.py
+++ b/spotseeker_server/test/hours/model.py
@@ -1,172 +1,149 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
+from django.test.utils import override_settings
from django.core.exceptions import ValidationError
import datetime
from spotseeker_server.models import Spot, SpotAvailableHours
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotHoursModelTest(TestCase):
"""Tests for Spot AvailableHours."""
def test_startMatchesEnd(self):
"""Tests that a Spot's AvailableHours cannot have zero length."""
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
- spot = Spot.objects.create(name="testing hours")
- with self.assertRaises(
- Exception,
- msg="Got an error trying to save a time"
- + "range with no time in it",
- ) as ex:
- SpotAvailableHours.objects.create(
- day="m", spot=spot, start_time="01:30", end_time="01:30"
- )
- self.assertEqual(
- ex.exception.args[0],
- "Invalid time range - start time must be before end time",
+ spot = Spot.objects.create(name="testing hours")
+ with self.assertRaises(
+ Exception,
+ msg="Got an error trying to save a time"
+ + "range with no time in it",
+ ) as ex:
+ SpotAvailableHours.objects.create(
+ day="m", spot=spot, start_time="01:30", end_time="01:30"
)
+ self.assertEqual(
+ ex.exception.args[0],
+ "Invalid time range - start time must be before end time",
+ )
def test_startAfterEnd(self):
"""Tests that a Spot's AvailableHours cannot end before they begin."""
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
- spot = Spot.objects.create(name="testing hours")
- with self.assertRaises(
- Exception,
- msg="Got an error trying to save a time"
- + "range with no time in it",
- ) as ex:
- SpotAvailableHours.objects.create(
- day="m", spot=spot, start_time="01:30", end_time="01:30"
- )
- self.assertEqual(
- ex.exception.args[0],
- "Invalid time range - start time must be before end time",
+ spot = Spot.objects.create(name="testing hours")
+ with self.assertRaises(
+ Exception,
+ msg="Got an error trying to save a time"
+ + "range with no time in it",
+ ) as ex:
+ SpotAvailableHours.objects.create(
+ day="m", spot=spot, start_time="01:30", end_time="01:30"
)
+ self.assertEqual(
+ ex.exception.args[0],
+ "Invalid time range - start time must be before end time",
+ )
def test_properRange(self):
"""Tests that having AvailableHours with a start time before the
end time saves properly.
"""
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
- spot = Spot.objects.create(name="testing hours")
- hours = SpotAvailableHours.objects.create(
- day="m", spot=spot, start_time="01:30", end_time="01:40"
- )
+ spot = Spot.objects.create(name="testing hours")
+ hours = SpotAvailableHours.objects.create(
+ day="m", spot=spot, start_time="01:30", end_time="01:40"
+ )
- self.assertEqual(hours.start_time, datetime.time(1, 30), "ok")
- self.assertEqual(hours.end_time, datetime.time(1, 40), "ok")
- self.assertEqual(hours.day, "m", "ok")
+ self.assertEqual(hours.start_time, datetime.time(1, 30), "ok")
+ self.assertEqual(hours.end_time, datetime.time(1, 40), "ok")
+ self.assertEqual(hours.day, "m", "ok")
def test_missingStart(self):
"""Tests that AvailableHours cannot be created with no start time."""
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
- spot = Spot.objects.create(name="testing hours")
- has_error = False
- try:
- hours = SpotAvailableHours.objects.create(
- spot=spot, day="m", end_time="01:30"
- )
- except ValidationError:
- has_error = True
-
- self.assertEqual(
- has_error,
- True,
- "Doesn't allow hours to be stored without a " "start time",
+ spot = Spot.objects.create(name="testing hours")
+ has_error = False
+ try:
+ hours = SpotAvailableHours.objects.create(
+ spot=spot, day="m", end_time="01:30"
)
+ except ValidationError:
+ has_error = True
+
+ self.assertEqual(
+ has_error,
+ True,
+ "Doesn't allow hours to be stored without a " "start time",
+ )
def test_missingEnd(self):
"""Tests that AvailableHours cannot be created with no end time."""
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
- spot = Spot.objects.create(name="testing hours")
- has_error = False
- try:
- hours = SpotAvailableHours.objects.create(
- spot=spot, day="m", start_time="01:30"
- )
- except ValidationError:
- has_error = True
-
- self.assertEqual(
- has_error,
- True,
- "Doesn't allow hours to be stored without " "an end time",
+ spot = Spot.objects.create(name="testing hours")
+ has_error = False
+ try:
+ hours = SpotAvailableHours.objects.create(
+ spot=spot, day="m", start_time="01:30"
)
+ except ValidationError:
+ has_error = True
+
+ self.assertEqual(
+ has_error,
+ True,
+ "Doesn't allow hours to be stored without " "an end time",
+ )
def test_missingHours(self):
"""Tests that AvailableHourse cannot be created with out a time range.
"""
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
- spot = Spot.objects.create(name="testing hours")
- has_error = False
- try:
- hours = SpotAvailableHours.objects.create(spot=spot, day="m")
- except ValidationError:
- has_error = True
-
- self.assertEqual(
- has_error,
- True,
- "Doesn't allow hours to be stored without hours",
- )
+ spot = Spot.objects.create(name="testing hours")
+ has_error = False
+ try:
+ hours = SpotAvailableHours.objects.create(spot=spot, day="m")
+ except ValidationError:
+ has_error = True
+
+ self.assertEqual(
+ has_error,
+ True,
+ "Doesn't allow hours to be stored without hours",
+ )
def test_missingDay(self):
""" Tests that AvailableHours cannot be \
created without a day of the week.
"""
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
- spot = Spot.objects.create(name="testing hours")
- has_error = False
- try:
- hours = SpotAvailableHours.objects.create(
- spot=spot, start_time="01:30", end_time="02:30"
- )
- except ValidationError:
- has_error = True
-
- self.assertEqual(
- has_error,
- True,
- "Doesn't allow hours to be stored without a day",
+ spot = Spot.objects.create(name="testing hours")
+ has_error = False
+ try:
+ hours = SpotAvailableHours.objects.create(
+ spot=spot, start_time="01:30", end_time="02:30"
)
+ except ValidationError:
+ has_error = True
+
+ self.assertEqual(
+ has_error,
+ True,
+ "Doesn't allow hours to be stored without a day",
+ )
def test_invalidDay(self):
"""Tests that AvailableHours cannot be created with a day that
doesn't exist as a day of the week.
"""
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
- spot = Spot.objects.create(name="testing hours")
- has_error = False
- try:
- hours = SpotAvailableHours.objects.create(
- spot=spot,
- day="Fail_day",
- start_time="01:30",
- end_time="02:30",
- )
- except Exception as e:
- has_error = True
-
- self.assertEqual(
- has_error,
- True,
- "Doesn't allow hours to be stored " "with an invalid day",
+ spot = Spot.objects.create(name="testing hours")
+ has_error = False
+ try:
+ hours = SpotAvailableHours.objects.create(
+ spot=spot,
+ day="Fail_day",
+ start_time="01:30",
+ end_time="02:30",
)
+ except Exception as e:
+ has_error = True
+
+ self.assertEqual(
+ has_error,
+ True,
+ "Doesn't allow hours to be stored " "with an invalid day",
+ )
diff --git a/spotseeker_server/test/hours/modify.py b/spotseeker_server/test/hours/modify.py
index cddc84c9..0d08bc40 100644
--- a/spotseeker_server/test/hours/modify.py
+++ b/spotseeker_server/test/hours/modify.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.conf import settings
diff --git a/spotseeker_server/test/hours/open_at.py b/spotseeker_server/test/hours/open_at.py
index 65aa804f..a0dd81e4 100644
--- a/spotseeker_server/test/hours/open_at.py
+++ b/spotseeker_server/test/hours/open_at.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
@@ -6,18 +6,16 @@
from django.test.client import Client
import simplejson as json
from datetime import datetime, timedelta
-import time
from django.test.utils import override_settings
from mock import patch
from spotseeker_server import models
-import mock
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotHoursOpenAtTest(TestCase):
"""Tests search requests for spots that are open at a particular time."""
- @mock.patch("spotseeker_server.views.search.SearchView.get_datetime")
+ @patch("spotseeker_server.views.search.SearchView.get_datetime")
def test_open_at(self, datetime_mock):
# Create a spot that isn't open now but will be in an hour.
spot = models.Spot.objects.create(name="This spot is open later")
diff --git a/spotseeker_server/test/hours/open_now.py b/spotseeker_server/test/hours/open_now.py
index c9bf38bc..87fe59d0 100644
--- a/spotseeker_server/test/hours/open_now.py
+++ b/spotseeker_server/test/hours/open_now.py
@@ -1,28 +1,24 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
from spotseeker_server.models import Spot, SpotAvailableHours
import simplejson as json
from datetime import datetime
import datetime as alternate_date
-import mock
-
from time import *
from django.test.utils import override_settings
from mock import patch
-from spotseeker_server import models
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotHoursOpenNowTest(TestCase):
"""Tests that we can tell if a Spot is available now,
based on it's Available Hours.
"""
- @mock.patch("spotseeker_server.views.search.SearchView.get_datetime")
+ @patch("spotseeker_server.views.search.SearchView.get_datetime")
def test_open_now(self, datetime_mock):
open_spot = Spot.objects.create(name="This spot is open now")
no_hours_spot = Spot.objects.create(name="This spot has no hours")
@@ -84,7 +80,7 @@ def test_open_now(self, datetime_mock):
)
self.assertEquals(has_open_spot, True, "Finds the open spot")
- @mock.patch("spotseeker_server.views.search.SearchView.get_datetime")
+ @patch("spotseeker_server.views.search.SearchView.get_datetime")
def test_thirty_sec_before_midnight(self, datetime_mock):
"""Tests when the user makes a request between 23:59 and 00:00."""
open_spot = Spot.objects.create(name="Spot open overnight")
diff --git a/spotseeker_server/test/hours/open_now_location.py b/spotseeker_server/test/hours/open_now_location.py
index 3616e264..7b112bbe 100644
--- a/spotseeker_server/test/hours/open_now_location.py
+++ b/spotseeker_server/test/hours/open_now_location.py
@@ -1,29 +1,26 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
from spotseeker_server.models import Spot, SpotAvailableHours
import simplejson as json
from datetime import datetime
import datetime as alternate_date
from decimal import *
-import mock
from time import *
from django.test.utils import override_settings
from mock import patch
-from spotseeker_server import models
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotHoursOpenNowLocationTest(TestCase):
"""Tests that available Spots that are in location range are returned
but available Spots outside the location range are not returned.
"""
- @mock.patch("spotseeker_server.views.search.SearchView.get_datetime")
+ @patch("spotseeker_server.views.search.SearchView.get_datetime")
def test_open_now(self, datetime_mock):
open_in_range_spot = Spot.objects.create(
name="This spot is open now",
diff --git a/spotseeker_server/test/hours/open_now_location_attributes.py b/spotseeker_server/test/hours/open_now_location_attributes.py
index adcf56d5..4231cc9c 100644
--- a/spotseeker_server/test/hours/open_now_location_attributes.py
+++ b/spotseeker_server/test/hours/open_now_location_attributes.py
@@ -1,29 +1,26 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
from spotseeker_server.models import Spot, SpotAvailableHours
import simplejson as json
from datetime import datetime
import datetime as alternate_date
from decimal import *
-import mock
+from mock import patch
from time import *
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotHoursOpenNowLocationAttributesTest(TestCase):
"""Tests that only available Spots with the requested attribute that are
in location range are returned.
"""
- @mock.patch("spotseeker_server.views.search.SearchView.get_datetime")
+ @patch("spotseeker_server.views.search.SearchView.get_datetime")
def test_open_now(self, datetime_mock):
open_in_range_matched_spot = Spot.objects.create(
name="Find this: Atlantic",
diff --git a/spotseeker_server/test/hours/open_until.py b/spotseeker_server/test/hours/open_until.py
index 31676a1f..2703860e 100644
--- a/spotseeker_server/test/hours/open_until.py
+++ b/spotseeker_server/test/hours/open_until.py
@@ -1,24 +1,21 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
from django.test.utils import override_settings
from django.test.client import Client
-import mock
from spotseeker_server.models import Spot, SpotAvailableHours
import simplejson as json
-from datetime import datetime, timedelta
+from datetime import datetime
import datetime as alternate_date
-import time
from mock import patch
-from spotseeker_server import models
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotHoursOpenUntilTest(TestCase):
"""Tests search requests for spots that are open at a particular time."""
- @mock.patch("spotseeker_server.views.search.SearchView.get_datetime")
+ @patch("spotseeker_server.views.search.SearchView.get_datetime")
def test_open_until(self, datetime_mock):
# Create a spot that isn't open now but will be in an hour.
spot = Spot.objects.create(name="This spot is open later")
diff --git a/spotseeker_server/test/hours/overlap.py b/spotseeker_server/test/hours/overlap.py
index 841bc188..5451f992 100644
--- a/spotseeker_server/test/hours/overlap.py
+++ b/spotseeker_server/test/hours/overlap.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.conf import settings
diff --git a/spotseeker_server/test/hours/post.py b/spotseeker_server/test/hours/post.py
index 9f71da26..e6d95b94 100644
--- a/spotseeker_server/test/hours/post.py
+++ b/spotseeker_server/test/hours/post.py
@@ -1,18 +1,14 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
-from spotseeker_server.models import Spot, SpotAvailableHours
import simplejson as json
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm",
)
diff --git a/spotseeker_server/test/hours/put.py b/spotseeker_server/test/hours/put.py
index 793abc4b..e66d0504 100644
--- a/spotseeker_server/test/hours/put.py
+++ b/spotseeker_server/test/hours/put.py
@@ -1,19 +1,16 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
-from spotseeker_server.models import Spot, SpotAvailableHours
+from spotseeker_server.models import Spot
import simplejson as json
from django.test.utils import override_settings
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm",
)
diff --git a/spotseeker_server/test/images/__init__.py b/spotseeker_server/test/images/__init__.py
index da5b319e..eac833e2 100644
--- a/spotseeker_server/test/images/__init__.py
+++ b/spotseeker_server/test/images/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from spotseeker_server.test import SpotServerTestCase
diff --git a/spotseeker_server/test/images/delete.py b/spotseeker_server/test/images/delete.py
index 8a2b1dc6..cad68d6f 100644
--- a/spotseeker_server/test/images/delete.py
+++ b/spotseeker_server/test/images/delete.py
@@ -1,23 +1,20 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import shutil
import tempfile
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
from django.core.files.uploadedfile import SimpleUploadedFile
from spotseeker_server.models import Spot, SpotImage
from os.path import abspath, dirname, isfile
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
TEST_ROOT = abspath(dirname(__file__))
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_AUTH_ADMINS=("demo_user",))
class SpotImageDELETETest(TestCase):
"""Tests DELETE of a SpotImage at /api/v1/spot//image/.
diff --git a/spotseeker_server/test/images/get.py b/spotseeker_server/test/images/get.py
index b8583f52..16a4683e 100644
--- a/spotseeker_server/test/images/get.py
+++ b/spotseeker_server/test/images/get.py
@@ -1,30 +1,22 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import shutil
import tempfile
+from io import BytesIO as IOStream
-try:
- from cStringIO import StringIO as IOStream
-except ModuleNotFoundError:
- from io import BytesIO as IOStream
-
-from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.test.client import Client
from django.test.utils import override_settings
-from mock import patch
from os.path import abspath, dirname
from PIL import Image
from spotseeker_server.models import Spot, SpotImage
-from spotseeker_server import models
-import random
TEST_ROOT = abspath(dirname(__file__))
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotImageGETTest(TestCase):
def setUp(self):
self.TEMP_DIR = tempfile.mkdtemp()
diff --git a/spotseeker_server/test/images/oauth_spot_info.py b/spotseeker_server/test/images/oauth_spot_info.py
deleted file mode 100644
index 31ef1361..00000000
--- a/spotseeker_server/test/images/oauth_spot_info.py
+++ /dev/null
@@ -1,259 +0,0 @@
-# Copyright 2023 UW-IT, University of Washington
-# SPDX-License-Identifier: Apache-2.0
-
-import secrets
-import shutil
-import tempfile
-
-from django.test import TestCase
-from django.test.utils import override_settings
-from django.test.client import Client
-from os.path import abspath, dirname, isfile
-from spotseeker_server.models import Spot, SpotImage, TrustedOAuthClient
-from django.core.files.uploadedfile import SimpleUploadedFile
-from django.conf import settings
-from PIL import Image
-from oauth_provider.models import Consumer
-import random
-import hashlib
-import time
-from oauthlib import oauth1
-import simplejson as json
-from mock import patch
-from spotseeker_server import models
-
-TEST_ROOT = abspath(dirname(__file__))
-
-
-@override_settings(SPOTSEEKER_AUTH_ADMINS=("pmichaud",))
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.oauth")
-class SpotResourceOAuthImageTest(TestCase):
- # In these tests the oauth signature for the same url could've been reused
- # However, for every single request a new oauth signature is issued
- # Emulating a situation, where, oauth signatures are time stamped
- def setUp(self):
- self.TEMP_DIR = tempfile.mkdtemp()
-
- # Setting up oauth
- consumer_name = "Test consumer"
- key = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
- secret = hashlib.sha1(
- "{0} - {1}".format(random.random(), time.time()).encode("utf-8")
- ).hexdigest()
-
- create_consumer = Consumer.objects.create(
- name=consumer_name, key=key, secret=secret
- )
- self.trusted_consumer = TrustedOAuthClient.objects.create(
- consumer=create_consumer,
- is_trusted=True,
- bypasses_user_authorization=False,
- )
-
- self.client = oauth1.Client(key, client_secret=secret)
-
- with self.settings(MEDIA_ROOT=self.TEMP_DIR):
- spot_post = Spot.objects.create(
- name="""This is to test posting images in the spot resource,
- with oauth"""
- )
- self.spot_post = spot_post
-
- spot_put = Spot.objects.create(
- name="""This is to test puting images in the spot resource,
- with oauth"""
- )
- self.spot_put = spot_put
- self.put_url = "http://testserver/api/v1/spot/{0}".format(
- self.spot_put.pk
- )
-
- # JPEG for PUT test
- jpeg = self.spot_put.spotimage_set.create(
- description="This is the JPEG PUT test",
- image=SimpleUploadedFile(
- "test_jpeg.jpg",
- open(
- "%s/../resources/test_jpeg.jpg" % TEST_ROOT, "rb"
- ).read(),
- "image/jpeg",
- ),
- )
-
- self.jpeg = jpeg
- self.jpeg_url = "%s/image/%s" % (self.put_url, self.jpeg.pk)
-
- spot_delete = Spot.objects.create(
- name="""This is to test deleting images in the spot resource,
- with oauth"""
- )
- self.spot_delete = spot_delete
- self.delete_url = "http://testserver/api/v1/spot/{0}".format(
- self.spot_delete.pk
- )
-
- # GIF for DELETE test
- gif = self.spot_delete.spotimage_set.create(
- description="This is the GIF DELETE test",
- image=SimpleUploadedFile(
- "test_gif.gif",
- open(
- "%s/../resources/test_gif.gif" % TEST_ROOT, "rb"
- ).read(),
- "image/gif",
- ),
- )
- self.gif = gif
- self.gif_url = "%s/image/%s" % (self.delete_url, self.gif.pk)
-
- def tearDown(self):
- shutil.rmtree(self.TEMP_DIR)
-
- # POST a PNG image, ensure that the spot has only 1 image
- # and user attributes are correct
- def test_oauth_attributes_post(self):
- with self.settings(MEDIA_ROOT=self.TEMP_DIR):
- _, headers, _ = self.client.sign(
- "http://testserver/api/v1/spot/%s" % self.spot_post.pk
- )
- c = Client()
- response = c.post(
- "/api/v1/spot/{0}/image".format(self.spot_post.pk),
- {
- "description": "This is the PNG POST test",
- "image": SimpleUploadedFile(
- "test_png.png",
- open(
- "%s/../resources/test_png.png" % TEST_ROOT,
- "rb",
- ).read(),
- "image/png",
- ),
- },
- HTTP_AUTHORIZATION=headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
-
- __, headers2, __ = self.client.sign(
- "http://testserver/api/v1/spot/%s" % self.spot_post.pk
- )
-
- response = c.get(
- "/api/v1/spot/{0}".format(self.spot_post.pk),
- HTTP_AUTHORIZATION=headers2["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
-
- spot_dict = json.loads(response.content)
-
- self.assertEquals(len(spot_dict["images"]), 1, "Has 1 image")
-
- self.assertEquals(
- spot_dict["images"][0]["upload_application"],
- "Test consumer",
- "Image has the proper upload application",
- )
- self.assertEquals(
- spot_dict["images"][0]["upload_user"],
- "pmichaud",
- "Image has the proper upload user",
- )
-
- # Get a JPEG image (image1), change it via PUT (image2), make sure that
- # PUT request was 200 & image1!=image2
- def test_oauth_attributes_put(self):
- with self.settings(MEDIA_ROOT=self.TEMP_DIR):
- _, headers, _ = self.client.sign(self.put_url)
- c = Client()
- response = c.get(
- self.put_url,
- HTTP_AUTHORIZATION=headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- spot_dict_before = json.loads(response.content)
-
- ____, get_headers, ____ = self.client.sign(self.jpeg_url)
- response = c.get(
- self.jpeg_url,
- HTTP_AUTHORIZATION=get_headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- etag = response["ETag"]
-
- new_name = "testing PUT name: {0}".format(random.random())
-
- __, put_headers, __ = self.client.sign(self.jpeg_url)
- response = c.put(
- self.jpeg_url,
- files={
- "description": new_name,
- "image": SimpleUploadedFile(
- "test_jpeg2.jpg",
- open(
- "%s/../resources/test_jpeg2.jpg" % TEST_ROOT, "rb"
- ).read(),
- "image/jpeg",
- ),
- },
- content_type="multipart/form-data; boundary=--aklsjf--",
- If_Match=etag,
- HTTP_AUTHORIZATION=put_headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- self.assertEquals(response.status_code, 200, "PUT was successful")
-
- ___, get_headers, ___ = self.client.sign(self.put_url)
- response = c.get(
- self.put_url,
- HTTP_AUTHORIZATION=get_headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- spot_dict_after = json.loads(response.content)
- self.assertNotEquals(
- spot_dict_before["images"][0],
- spot_dict_after["images"][0],
- "Images weren't equal after PUT",
- )
-
- # Delete a GIF image, confirm that DELETE is succesful,
- # further GET & DELETE return 404, image no longer exists as a file
- def test_oauth_attributes_delete(self):
- with self.settings(MEDIA_ROOT=self.TEMP_DIR):
- _, headers, _ = self.client.sign(self.gif_url)
- c = Client()
- response = c.get(
- self.gif_url,
- HTTP_AUTHORIZATION=headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- etag = response["ETag"]
-
- __, delete_headers, __ = self.client.sign(self.gif_url)
- response = c.delete(
- self.gif_url,
- If_Match=etag,
- HTTP_AUTHORIZATION=delete_headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- self.assertEquals(response.status_code, 200)
-
- ___, get_headers, ___ = self.client.sign(self.gif_url)
- response = c.get(
- self.gif_url,
- HTTP_AUTHORIZATION=get_headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- self.assertEquals(response.status_code, 404)
-
- ____, delete2_headers, ____ = self.client.sign(self.gif_url)
- response = c.delete(
- self.gif_url,
- If_Match=etag,
- HTTP_AUTHORIZATION=delete2_headers["Authorization"],
- HTTP_X_OAUTH_USER="pmichaud",
- )
- self.assertEqual(response.status_code, 404)
-
- self.assertEqual(isfile(self.gif.image.path), False)
diff --git a/spotseeker_server/test/images/post.py b/spotseeker_server/test/images/post.py
index 29ea1463..c802d4ae 100644
--- a/spotseeker_server/test/images/post.py
+++ b/spotseeker_server/test/images/post.py
@@ -1,23 +1,19 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
-from django.conf import settings
from django.test import TestCase
from django.test.client import Client
from django.test.utils import override_settings
-from mock import patch
from os.path import abspath, dirname
-from spotseeker_server import models
from spotseeker_server.models import Spot
import json
-import random
import shutil
import tempfile
TEST_ROOT = abspath(dirname(__file__))
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_AUTH_ADMINS=("demo_user",))
class SpotImagePOSTTest(TestCase):
"""Tests POSTing to /api/v1/spot//image."""
diff --git a/spotseeker_server/test/images/put.py b/spotseeker_server/test/images/put.py
index 7f9eeac4..8b329e7d 100644
--- a/spotseeker_server/test/images/put.py
+++ b/spotseeker_server/test/images/put.py
@@ -1,24 +1,21 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
-from django.test.client import Client, encode_multipart
+from django.test.client import Client
from django.core.files.uploadedfile import SimpleUploadedFile
+from django.test.utils import override_settings
from spotseeker_server.models import Spot, SpotImage
from os.path import abspath, dirname
import os
import random
import tempfile
import shutil
-from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
TEST_ROOT = abspath(dirname(__file__))
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_AUTH_ADMINS=("demo_user",))
class SpotImagePUTTest(TestCase):
"""Tests updating a SpotImage by PUTting to
diff --git a/spotseeker_server/test/images/spot_info.py b/spotseeker_server/test/images/spot_info.py
index 9ddc5427..02dc9835 100644
--- a/spotseeker_server/test/images/spot_info.py
+++ b/spotseeker_server/test/images/spot_info.py
@@ -1,18 +1,15 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import shutil
import tempfile
-from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.test.client import Client
from django.test.utils import override_settings
-from mock import patch
from os.path import abspath, dirname
from PIL import Image
-from spotseeker_server import models
from spotseeker_server.models import Spot, SpotImage
import datetime
import simplejson as json
@@ -21,7 +18,7 @@
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm",
)
diff --git a/spotseeker_server/test/images/thumb.py b/spotseeker_server/test/images/thumb.py
index c13450c1..a2a5ee04 100644
--- a/spotseeker_server/test/images/thumb.py
+++ b/spotseeker_server/test/images/thumb.py
@@ -1,13 +1,9 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import shutil
import tempfile
-
-try:
- from cStringIO import StringIO as IOStream
-except ModuleNotFoundError:
- from io import BytesIO as IOStream
+from io import BytesIO as IOStream
from spotseeker_server.test.images import ImageTestCase
from django.core.files.uploadedfile import SimpleUploadedFile
@@ -23,7 +19,7 @@
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_AUTH_ADMINS=("demo_user",),
)
class ImageThumbTest(ImageTestCase):
diff --git a/spotseeker_server/test/item/form.py b/spotseeker_server/test/item/form.py
index 429e6231..5d68ecee 100644
--- a/spotseeker_server/test/item/form.py
+++ b/spotseeker_server/test/item/form.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
@@ -14,7 +14,7 @@
@override_settings(
- SPOTSEEKER_AUTH_MODULE='spotseeker_server.auth.all_ok',
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM=DEFAULT_FORM,
SPOTSEEKER_SPOTEXTENDEDINFO_FORM=DEFAULT_EI_FORM)
class ItemFormsTest(TestCase):
diff --git a/spotseeker_server/test/item/image_delete.py b/spotseeker_server/test/item/image_delete.py
index b8f30571..1d6d5544 100644
--- a/spotseeker_server/test/item/image_delete.py
+++ b/spotseeker_server/test/item/image_delete.py
@@ -1,24 +1,20 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import shutil
import tempfile
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
from django.core.files.uploadedfile import SimpleUploadedFile
from spotseeker_server.models import Item, ItemImage, Spot
-from os.path import abspath, dirname, isfile
+from os.path import abspath, dirname
from django.test.utils import override_settings
-from mock import patch
-from django.core import cache
-from spotseeker_server import models
TEST_ROOT = abspath(dirname(__file__))
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_AUTH_ADMINS=("demo_user",))
class ItemImageDELETETest(TestCase):
"""Tests DELETE of a ItemImage at /api/v1/item/- /image/.
diff --git a/spotseeker_server/test/item/image_get.py b/spotseeker_server/test/item/image_get.py
index 81173350..e4cb3953 100644
--- a/spotseeker_server/test/item/image_get.py
+++ b/spotseeker_server/test/item/image_get.py
@@ -1,31 +1,22 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import shutil
import tempfile
+from io import BytesIO as IOStream
-try:
- from cStringIO import StringIO as IOStream
-except ModuleNotFoundError:
- from io import BytesIO as IOStream
-
-from django.conf import settings
-from django.core import cache
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.test.client import Client
from django.test.utils import override_settings
-from mock import patch
from os.path import abspath, dirname
from PIL import Image
from spotseeker_server.models import Item, ItemImage
-from spotseeker_server import models
-import random
TEST_ROOT = abspath(dirname(__file__))
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class ItemImageGETTest(TestCase):
dummy_cache_setting = {
diff --git a/spotseeker_server/test/item/image_post.py b/spotseeker_server/test/item/image_post.py
index fa6997fe..57e411f2 100644
--- a/spotseeker_server/test/item/image_post.py
+++ b/spotseeker_server/test/item/image_post.py
@@ -1,24 +1,19 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
-from django.conf import settings
-from django.core import cache
from django.test import TestCase
from django.test.client import Client
from django.test.utils import override_settings
-from mock import patch
from os.path import abspath, dirname
-from spotseeker_server import models
from spotseeker_server.models import Item, Spot
import json
-import random
import shutil
import tempfile
TEST_ROOT = abspath(dirname(__file__))
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_AUTH_ADMINS=("demo_user",))
class ItemImagePOSTTest(TestCase):
"""Tests POSTing to /api/v1/item/
- /image."""
diff --git a/spotseeker_server/test/item/image_put.py b/spotseeker_server/test/item/image_put.py
index 4ccbb9fe..57314efa 100644
--- a/spotseeker_server/test/item/image_put.py
+++ b/spotseeker_server/test/item/image_put.py
@@ -1,24 +1,21 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
-from django.test.client import Client, encode_multipart
+from django.test.client import Client
from django.core.files.uploadedfile import SimpleUploadedFile
+from django.test.utils import override_settings
from spotseeker_server.models import Item, ItemImage, Spot
from os.path import abspath, dirname
import os
import random
import tempfile
import shutil
-from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
TEST_ROOT = abspath(dirname(__file__))
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_AUTH_ADMINS=("demo_user",))
class ItemImagePUTTest(TestCase):
"""Tests updating a ItemImage by PUTting to
diff --git a/spotseeker_server/test/item/image_thumbnail.py b/spotseeker_server/test/item/image_thumbnail.py
index 51e69886..4ea419f0 100644
--- a/spotseeker_server/test/item/image_thumbnail.py
+++ b/spotseeker_server/test/item/image_thumbnail.py
@@ -1,30 +1,22 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import shutil
import tempfile
-
-try:
- from cStringIO import StringIO as IOStream
-except ModuleNotFoundError:
- from io import BytesIO as IOStream
+from io import BytesIO as IOStream
from django.test import TestCase
-from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test.client import Client
+from django.test.utils import override_settings
from spotseeker_server.models import Item, ItemImage, Spot
from PIL import Image
from os.path import abspath, dirname
-from django.test.utils import override_settings
-from mock import patch
-from django.core import cache
-from spotseeker_server import models
TEST_ROOT = abspath(dirname(__file__))
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_AUTH_ADMINS=("demo_user",))
class ItemImageThumbTest(TestCase):
diff --git a/spotseeker_server/test/item/model.py b/spotseeker_server/test/item/model.py
index b0395f94..0356c697 100644
--- a/spotseeker_server/test/item/model.py
+++ b/spotseeker_server/test/item/model.py
@@ -1,9 +1,8 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from builtins import range
-from django.conf import settings
from django.test import TestCase
from django.test.utils import override_settings
import random
@@ -13,7 +12,7 @@
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm",
)
diff --git a/spotseeker_server/test/long_message.py b/spotseeker_server/test/long_message.py
index 20de4f6f..115f1e03 100644
--- a/spotseeker_server/test/long_message.py
+++ b/spotseeker_server/test/long_message.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
'''
diff --git a/spotseeker_server/test/models.py b/spotseeker_server/test/models.py
index bf1c2fc4..00598c4a 100644
--- a/spotseeker_server/test/models.py
+++ b/spotseeker_server/test/models.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import shutil
diff --git a/spotseeker_server/test/no_rest_methods.py b/spotseeker_server/test/no_rest_methods.py
index 8896302e..e797c1b2 100644
--- a/spotseeker_server/test/no_rest_methods.py
+++ b/spotseeker_server/test/no_rest_methods.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
diff --git a/spotseeker_server/test/oauth.py b/spotseeker_server/test/oauth.py
new file mode 100644
index 00000000..b9c3711e
--- /dev/null
+++ b/spotseeker_server/test/oauth.py
@@ -0,0 +1,203 @@
+# Copyright 2024 UW-IT, University of Washington
+# SPDX-License-Identifier: Apache-2.0
+
+from django.test import TestCase
+from django.test.utils import override_settings
+from spotseeker_server.models import Spot, Client
+import simplejson as json
+from datetime import timedelta
+from django.utils import timezone
+from oauth2_provider.models import AccessToken, Application
+
+
+@override_settings(
+ SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot.DefaultSpotForm"
+)
+@override_settings(
+ SPOTSEEKER_SPOTEXTENDEDINFO_FORM="spotseeker_server.default_forms.spot."
+ "DefaultSpotExtendedInfoForm"
+)
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=True)
+class SpotAuthOAuth(TestCase):
+ def setUp(self):
+ spot = Spot.objects.create(
+ name="This is for testing the oauth module", capacity=10
+ )
+ self.spot = spot
+ self.url = "/api/v1/spot/%s" % self.spot.pk
+
+ def tearDown(self) -> None:
+ AccessToken.objects.all().delete()
+ Application.objects.all().delete()
+ Client.objects.all().delete()
+ Spot.objects.all().delete()
+
+ return super().tearDown()
+
+ def _create_auth_header(self, token: str) -> str:
+ return "Bearer " + token
+
+ def _create_token(self, client: Client, expiry: int = 300,
+ scope: str = 'read write') -> AccessToken:
+ app = Application.objects.create(
+ client_type=Application.CLIENT_CONFIDENTIAL,
+ authorization_grant_type=Application.GRANT_CLIENT_CREDENTIALS,
+ name="Test app",
+ user=client,
+ )
+
+ token = AccessToken.objects.create(
+ user=client,
+ scope=scope,
+ expires=timezone.now() + timedelta(seconds=expiry),
+ token="testtoken",
+ application=app,
+ )
+
+ return token
+
+ def test_get_no_oauth(self):
+ c = self.client
+ response = c.get(self.url)
+ self.assertEquals(
+ response.status_code, 401, "No access to GET w/o oauth"
+ )
+
+ def test_valid_oauth(self):
+ consumer_name = "Test consumer"
+
+ auth_client = Client.objects.create(
+ username=consumer_name, name=consumer_name,
+ client_id="fake_id", client_secret="fake_secret"
+ )
+ auth_client.get_client_credential()
+ auth_client.save()
+
+ token = self._create_auth_header(
+ self._create_token(auth_client).token
+ )
+
+ c = self.client
+
+ response = c.get(self.url, HTTP_AUTHORIZATION=token)
+
+ self.assertEquals(
+ response.status_code,
+ 200,
+ "Got a 200 w/ a proper oauth client connection",
+ )
+
+ spot_dict = json.loads(response.content)
+
+ self.assertEquals(
+ spot_dict["id"], self.spot.pk, "Got the right spot back from oauth"
+ )
+
+ def test_invalid_oauth(self):
+ consumer_name = "Test consumer"
+
+ auth_client = Client.objects.create(
+ username=consumer_name, name=consumer_name,
+ client_id="fake_id", client_secret="fake_secret"
+ )
+ auth_client.get_client_credential()
+ auth_client.save()
+
+ token = self._create_auth_header(
+ self._create_token(auth_client).token
+ )
+
+ c = self.client
+ response = c.get(self.url, HTTP_AUTHORIZATION=token + "BAD")
+
+ self.assertEquals(
+ response.status_code,
+ 401,
+ "Got a 401 w/ an invented oauth client id",
+ )
+
+ def test_put_no_oauth(self):
+ c = self.client
+
+ response = c.get(self.url)
+
+ etag = self.spot.etag
+
+ spot_dict = self.spot.json_data_structure()
+ spot_dict["name"] = "Failing to modify oauth"
+
+ response = c.put(
+ self.url,
+ json.dumps(spot_dict),
+ content_type="application/json",
+ If_Match=etag,
+ )
+ self.assertEquals(
+ response.status_code, 401, "Rejects a PUT w/o oauth info"
+ )
+
+ def test_put_expired_oauth(self):
+ consumer_name = "Expired consumer"
+
+ unauth_client = Client.objects.create(
+ username=consumer_name, name=consumer_name,
+ client_id="fake_id", client_secret="fake_secret"
+ )
+ unauth_client.get_client_credential()
+ unauth_client.save()
+
+ token = self._create_auth_header(
+ self._create_token(unauth_client, -1).token
+ )
+
+ c = self.client
+ response = c.get(self.url, HTTP_AUTHORIZATION=token)
+
+ self.assertEquals(
+ response.status_code,
+ 401,
+ "Rejects a GET from an expired oauth client",
+ )
+
+ def test_put_read_only_oauth(self):
+ consumer_name = "Read-only consumer"
+
+ unauth_client = Client.objects.create(
+ username=consumer_name, name=consumer_name,
+ client_id="fake_id", client_secret="fake_secret"
+ )
+ unauth_client.get_client_credential()
+ unauth_client.save()
+
+ token = self._create_auth_header(
+ self._create_token(unauth_client, scope='read').token
+ )
+
+ c = self.client
+ response = c.get(self.url, HTTP_AUTHORIZATION=token)
+
+ self.assertEquals(
+ response.status_code,
+ 200,
+ "Accepts a GET from a read-only oauth client",
+ )
+
+ etag = response["ETag"]
+
+ spot_dict = json.loads(response.content)
+ spot_dict["name"] = "Failing to modify oauth"
+ spot_dict["location"] = {"latitude": 55, "longitude": -30}
+
+ response = c.put(
+ self.url,
+ json.dumps(spot_dict),
+ content_type="application/json",
+ If_Match=etag,
+ HTTP_AUTHORIZATION=token,
+ )
+
+ self.assertEquals(
+ response.status_code,
+ 403,
+ "Rejects a PUT from a non-trusted oauth client",
+ )
diff --git a/spotseeker_server/test/schema.py b/spotseeker_server/test/schema.py
index cfe2d935..55b9b6a1 100644
--- a/spotseeker_server/test/schema.py
+++ b/spotseeker_server/test/schema.py
@@ -1,16 +1,14 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from spotseeker_server.models import *
from django.test.client import Client
from django.test import TestCase
import simplejson as json
-from mock import patch
-from spotseeker_server import models
from django.test.utils import override_settings
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm"
diff --git a/spotseeker_server/test/search/buildings.py b/spotseeker_server/test/search/buildings.py
index adacadf4..1d4a1fd4 100644
--- a/spotseeker_server/test/search/buildings.py
+++ b/spotseeker_server/test/search/buildings.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from unittest import skipIf
@@ -8,7 +8,7 @@
import simplejson as json
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class BuildingSearchTest(SpotServerTestCase):
"""Tests the /api/v1/buildings interface."""
@@ -73,7 +73,7 @@ def test_content_type(self):
def test_get_all_buildings(self):
c = self.client
- # TODO: Even though this works, we do not recommend using this method.
+ # Even though this works, we do not recommend using this method.
# You should be passing at least one query param.
response = c.get("/api/v1/buildings")
buildings = json.loads(response.content)
diff --git a/spotseeker_server/test/search/capacity.py b/spotseeker_server/test/search/capacity.py
index 52e634ed..82f3549f 100644
--- a/spotseeker_server/test/search/capacity.py
+++ b/spotseeker_server/test/search/capacity.py
@@ -1,16 +1,12 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from spotseeker_server.test import SpotServerTestCase
-from django.conf import settings
-from spotseeker_server.models import Spot, SpotExtendedInfo, SpotType
import simplejson as json
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotSearchCapacityTest(SpotServerTestCase):
def test_capacity(self):
diff --git a/spotseeker_server/test/search/distance.py b/spotseeker_server/test/search/distance.py
index e780ed38..c0b3644b 100644
--- a/spotseeker_server/test/search/distance.py
+++ b/spotseeker_server/test/search/distance.py
@@ -1,18 +1,15 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
+from django.test.utils import override_settings
from spotseeker_server.models import Spot
import simplejson as json
from decimal import *
-from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotSearchDistanceTest(TestCase):
def test_invalid_latitude(self):
c = Client()
diff --git a/spotseeker_server/test/search/distance_fields.py b/spotseeker_server/test/search/distance_fields.py
index aeb0c1af..4314aec5 100644
--- a/spotseeker_server/test/search/distance_fields.py
+++ b/spotseeker_server/test/search/distance_fields.py
@@ -1,66 +1,64 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
+from django.test.utils import override_settings
from spotseeker_server.models import Spot
import simplejson as json
from decimal import *
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotSearchDistanceFieldTest(TestCase):
def test_distances(self):
# Spots are in the atlantic to make them less likely
# to collide with actual spots
- with self.settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok"
- ):
- center_lat = 31.000000
- center_long = -41.000000
+ center_lat = 31.000000
+ center_long = -41.000000
- inner_top = Spot.objects.create(
- name="Atlantic Location 1",
- latitude=Decimal("31.0000898315"),
- longitude=Decimal("-41.0"),
- )
- inner_top.save()
+ inner_top = Spot.objects.create(
+ name="Atlantic Location 1",
+ latitude=Decimal("31.0000898315"),
+ longitude=Decimal("-41.0"),
+ )
+ inner_top.save()
- inner_top2 = Spot.objects.create(
- name="Alternate name of AL1",
- latitude=Decimal("31.0000898315"),
- longitude=Decimal("-41.0"),
- )
- inner_top2.save()
+ inner_top2 = Spot.objects.create(
+ name="Alternate name of AL1",
+ latitude=Decimal("31.0000898315"),
+ longitude=Decimal("-41.0"),
+ )
+ inner_top2.save()
- mid_top = Spot.objects.create(
- name="Atlantic Location 2",
- latitude=Decimal("34.0004491576"),
- longitude=Decimal("-44.0"),
- )
- mid_top.save()
+ mid_top = Spot.objects.create(
+ name="Atlantic Location 2",
+ latitude=Decimal("34.0004491576"),
+ longitude=Decimal("-44.0"),
+ )
+ mid_top.save()
- c = Client()
- response = c.get(
- "/api/v1/spot",
- {
- "center_latitude": center_lat,
- "center_longitude": center_long,
- "distance": 12,
- "name": "Atlantic",
- },
- )
- self.assertEquals(
- response.status_code, 200, "Accepts the distance query"
- )
- self.assertEquals(
- response["Content-Type"],
- "application/json",
- "Has the json header",
- )
- spots = json.loads(response.content)
- self.assertEquals(len(spots), 1, "Returns 1 spot")
+ c = Client()
+ response = c.get(
+ "/api/v1/spot",
+ {
+ "center_latitude": center_lat,
+ "center_longitude": center_long,
+ "distance": 12,
+ "name": "Atlantic",
+ },
+ )
+ self.assertEquals(
+ response.status_code, 200, "Accepts the distance query"
+ )
+ self.assertEquals(
+ response["Content-Type"],
+ "application/json",
+ "Has the json header",
+ )
+ spots = json.loads(response.content)
+ self.assertEquals(len(spots), 1, "Returns 1 spot")
- self.assertEquals(
- spots[0]["id"], inner_top.pk, "Found the inner Atlantic spot"
- )
+ self.assertEquals(
+ spots[0]["id"], inner_top.pk, "Found the inner Atlantic spot"
+ )
diff --git a/spotseeker_server/test/search/fields.py b/spotseeker_server/test/search/fields.py
index 293078a9..b32f49b0 100644
--- a/spotseeker_server/test/search/fields.py
+++ b/spotseeker_server/test/search/fields.py
@@ -1,17 +1,13 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from spotseeker_server.test import SpotServerTestCase
-from django.conf import settings
-from django.test.client import Client
from spotseeker_server.models import Spot, SpotExtendedInfo, SpotType
import simplejson as json
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotSearchFieldTest(SpotServerTestCase):
@classmethod
def setUpClass(self):
diff --git a/spotseeker_server/test/search/item.py b/spotseeker_server/test/search/item.py
index da0dd924..3774a28c 100644
--- a/spotseeker_server/test/search/item.py
+++ b/spotseeker_server/test/search/item.py
@@ -1,9 +1,7 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
-from django.test.client import Client
from django.test.utils import override_settings
from spotseeker_server.models import (
Spot,
@@ -12,21 +10,9 @@
ItemExtendedInfo,
)
import simplejson as json
-from mock import patch
-from spotseeker_server import models
-try:
- from unittest import skip
-except ImportError:
- def skip(*args, **kwargs):
- def inner(self):
- pass
-
- return inner
-
-
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotSearchItemTest(TestCase):
"""
Tests on the implemented item filters. Checks whether the new filters work
diff --git a/spotseeker_server/test/search/limit.py b/spotseeker_server/test/search/limit.py
index e50e2781..a58bd86b 100644
--- a/spotseeker_server/test/search/limit.py
+++ b/spotseeker_server/test/search/limit.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
@@ -6,11 +6,9 @@
from spotseeker_server.models import Spot
import simplejson as json
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotSearchLimitTest(TestCase):
def setUp(self):
num_spots = 25
diff --git a/spotseeker_server/test/search/noise_level.py b/spotseeker_server/test/search/noise_level.py
index 0c6dce14..dc1812d5 100644
--- a/spotseeker_server/test/search/noise_level.py
+++ b/spotseeker_server/test/search/noise_level.py
@@ -1,8 +1,7 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.test.client import Client
from django.test.utils import override_settings
import simplejson as json
from spotseeker_server.models import Spot, SpotExtendedInfo
@@ -16,7 +15,7 @@ def spot_with_noise_level(name, noise_level):
return spot
-@override_settings(SPOTSEEKER_AUTH_MODULE='spotseeker_server.auth.all_ok')
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class NoiseLevelTestCase(TestCase):
@classmethod
diff --git a/spotseeker_server/test/search/time.py b/spotseeker_server/test/search/time.py
index 32537b95..72c1609c 100644
--- a/spotseeker_server/test/search/time.py
+++ b/spotseeker_server/test/search/time.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
@@ -17,7 +17,7 @@ def new_hours(spot, day, start, end):
)
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
class SpotSearchTimeTest(TestCase):
def test_SameDayTimeInSerial(self):
"""Simple open hours test with a single date range per spot"""
diff --git a/spotseeker_server/test/search/uw_buildings.py b/spotseeker_server/test/search/uw_buildings.py
index 20ffdab4..a1de8e52 100644
--- a/spotseeker_server/test/search/uw_buildings.py
+++ b/spotseeker_server/test/search/uw_buildings.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
import simplejson as json
@@ -9,7 +9,7 @@
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SEARCH_FILTERS=(
"spotseeker_server.org_filters.uw_search.Filter",
),
diff --git a/spotseeker_server/test/search/uw_noise_level.py b/spotseeker_server/test/search/uw_noise_level.py
index 261fc8dd..cbbc20bc 100644
--- a/spotseeker_server/test/search/uw_noise_level.py
+++ b/spotseeker_server/test/search/uw_noise_level.py
@@ -1,8 +1,7 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.test.client import Client
from django.test.utils import override_settings
import simplejson as json
from spotseeker_server.models import Spot, SpotExtendedInfo
@@ -17,7 +16,7 @@ def spot_with_noise_level(name, noise_level):
return spot
-@override_settings(SPOTSEEKER_AUTH_MODULE='spotseeker_server.auth.all_ok',
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SEARCH_FILTERS=(
'spotseeker_server.org_filters.uw_search.Filter',))
class UWNoiseLevelTestCase(TestCase):
diff --git a/spotseeker_server/test/search/view_methods.py b/spotseeker_server/test/search/view_methods.py
index 7a646e25..684b3d9a 100644
--- a/spotseeker_server/test/search/view_methods.py
+++ b/spotseeker_server/test/search/view_methods.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
diff --git a/spotseeker_server/test/spot_caching.py b/spotseeker_server/test/spot_caching.py
index 5cf59723..a2011707 100644
--- a/spotseeker_server/test/spot_caching.py
+++ b/spotseeker_server/test/spot_caching.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase, override_settings
diff --git a/spotseeker_server/test/spot_delete.py b/spotseeker_server/test/spot_delete.py
index fac6d030..7c5d52f4 100644
--- a/spotseeker_server/test/spot_delete.py
+++ b/spotseeker_server/test/spot_delete.py
@@ -1,17 +1,14 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
from spotseeker_server.models import Spot
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm",
)
diff --git a/spotseeker_server/test/spot_form.py b/spotseeker_server/test/spot_form.py
index 1807a4fc..f24142e8 100644
--- a/spotseeker_server/test/spot_form.py
+++ b/spotseeker_server/test/spot_form.py
@@ -1,15 +1,14 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
from spotseeker_server.default_forms.spot import DefaultSpotForm
from spotseeker_server.forms.spot import SpotForm
-from django.conf import settings
from django.test.utils import override_settings
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm",
SPOTSEEKER_SPOTEXTENDEDINFO_FORM="spotseeker_server.default_forms.spot."
diff --git a/spotseeker_server/test/spot_get.py b/spotseeker_server/test/spot_get.py
index 58794014..bad26e57 100644
--- a/spotseeker_server/test/spot_get.py
+++ b/spotseeker_server/test/spot_get.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from builtins import range
@@ -15,7 +15,7 @@
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm",
)
diff --git a/spotseeker_server/test/spot_model.py b/spotseeker_server/test/spot_model.py
index 2c004552..e3e272a8 100644
--- a/spotseeker_server/test/spot_model.py
+++ b/spotseeker_server/test/spot_model.py
@@ -1,18 +1,15 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
-from django.conf import settings
import random
from spotseeker_server.models import Spot
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm",
)
diff --git a/spotseeker_server/test/spot_post.py b/spotseeker_server/test/spot_post.py
index 5a847c27..88d8f209 100644
--- a/spotseeker_server/test/spot_post.py
+++ b/spotseeker_server/test/spot_post.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
@@ -11,19 +11,9 @@
from past.builtins import basestring
-try:
- from unittest import skip
-except ImportError:
-
- def skip(*args, **kwargs):
- def inner(self):
- pass
-
- return inner
-
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm",
SPOTSEEKER_SPOTEXTENDEDINFO_FORM="spotseeker_server.default_forms.spot."
diff --git a/spotseeker_server/test/spot_put.py b/spotseeker_server/test/spot_put.py
index a3fab44e..7a29598e 100644
--- a/spotseeker_server/test/spot_put.py
+++ b/spotseeker_server/test/spot_put.py
@@ -1,14 +1,10 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
-from django.contrib.auth.models import User
from django.test import TestCase
-from django.conf import settings
from django.test.client import Client
from spotseeker_server.models import Spot, Item
from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
import simplejson as json
import random
from spotseeker_server.test import utils_test
@@ -16,18 +12,8 @@
from past.builtins import basestring
-try:
- from unittest import skip
-except ImportError:
- def skip(*args, **kwargs):
- def inner(self):
- pass
-
- return inner
-
-
-@override_settings(SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok")
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(
SPOTSEEKER_SPOT_FORM="spotseeker_server.default_forms.spot."
"DefaultSpotForm"
diff --git a/spotseeker_server/test/techloan/__init__.py b/spotseeker_server/test/techloan/__init__.py
index a3d5e32f..a7cf897c 100644
--- a/spotseeker_server/test/techloan/__init__.py
+++ b/spotseeker_server/test/techloan/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from spotseeker_server.test import SpotServerTestCase
diff --git a/spotseeker_server/test/techloan/sync_techloan.py b/spotseeker_server/test/techloan/sync_techloan.py
index 358eb6ff..c08f5e55 100644
--- a/spotseeker_server/test/techloan/sync_techloan.py
+++ b/spotseeker_server/test/techloan/sync_techloan.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from io import StringIO
diff --git a/spotseeker_server/test/utils_test.py b/spotseeker_server/test/utils_test.py
index 675afc7d..67aa7251 100644
--- a/spotseeker_server/test/utils_test.py
+++ b/spotseeker_server/test/utils_test.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
"""Provide useful methods for testing
diff --git a/spotseeker_server/test/uw_spot/schema.py b/spotseeker_server/test/uw_spot/schema.py
index 120ddd97..51e2dae3 100644
--- a/spotseeker_server/test/uw_spot/schema.py
+++ b/spotseeker_server/test/uw_spot/schema.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test.utils import override_settings
@@ -8,12 +8,11 @@
import simplejson as json
-ALL_OK = "spotseeker_server.auth.all_ok"
UW_SPOT_FORM = "spotseeker_server.org_forms.uw_spot.UWSpotForm"
UW_EXT_INFO_FORM = "spotseeker_server.org_forms.uw_spot.UWSpotExtendedInfoForm"
-@override_settings(SPOTSEEKER_AUTH_MODULE=ALL_OK)
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_SPOT_FORM=UW_SPOT_FORM)
@override_settings(SPOTSEEKER_SPOTEXTENDEDINFO_FORM=UW_EXT_INFO_FORM)
class UWSpotSchemaTest(TestCase):
diff --git a/spotseeker_server/test/uw_spot/spot_form.py b/spotseeker_server/test/uw_spot/spot_form.py
index 2518f908..63b3e3b5 100644
--- a/spotseeker_server/test/uw_spot/spot_form.py
+++ b/spotseeker_server/test/uw_spot/spot_form.py
@@ -1,18 +1,16 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TestCase
+from django.test.utils import override_settings
from spotseeker_server.org_forms.uw_spot import UWSpotForm
from spotseeker_server.org_forms.uw_spot import UWSpotExtendedInfoForm
-from django.conf import settings
-from django.test.utils import override_settings
-ALL_OK = "spotseeker_server.auth.all_ok"
UW_SPOT_FORM = "spotseeker_server.org_forms.uw_spot.UWSpotForm"
UW_EXT_INFO_FORM = "spotseeker_server.org_forms.uw.spot.UWSpotExtendedInfoForm"
-@override_settings(SPOTSEEKER_AUTH_MODULE=ALL_OK)
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_SPOT_FORM=UW_SPOT_FORM)
@override_settings(SPOTSEEKER_SPOTEXTENDEDINFO_FORM=UW_EXT_INFO_FORM)
class UWSpotFormTest(TestCase):
diff --git a/spotseeker_server/test/uw_spot/spot_post.py b/spotseeker_server/test/uw_spot/spot_post.py
index 34d167f3..6d6acd73 100644
--- a/spotseeker_server/test/uw_spot/spot_post.py
+++ b/spotseeker_server/test/uw_spot/spot_post.py
@@ -1,23 +1,19 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TransactionTestCase
-from django.conf import settings
from django.test.client import Client
+from django.test.utils import override_settings
from spotseeker_server.models import Spot
import simplejson as json
import random
-from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
-ALL_OK = "spotseeker_server.auth.all_ok"
UW_SPOT_FORM = "spotseeker_server.org_forms.uw_spot.UWSpotForm"
UW_EXT_INFO_FORM = "spotseeker_server.org_forms.uw_spot.UWSpotExtendedInfoForm"
-@override_settings(SPOTSEEKER_AUTH_MODULE=ALL_OK)
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_SPOT_FORM=UW_SPOT_FORM)
@override_settings(SPOTSEEKER_SPOTEXTENDEDINFO_FORM=UW_EXT_INFO_FORM)
@override_settings(SPOTSEEKER_AUTH_ADMINS=("demo_user",))
diff --git a/spotseeker_server/test/uw_spot/spot_put.py b/spotseeker_server/test/uw_spot/spot_put.py
index 465c5018..c5846649 100644
--- a/spotseeker_server/test/uw_spot/spot_put.py
+++ b/spotseeker_server/test/uw_spot/spot_put.py
@@ -1,25 +1,21 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django.test import TransactionTestCase
-from django.conf import settings
from django.test.client import Client
+from django.test.utils import override_settings
from spotseeker_server.models import Spot, SpotExtendedInfo
import simplejson as json
import random
-from django.test.utils import override_settings
-from mock import patch
-from spotseeker_server import models
from spotseeker_server.test import utils_test
from past.builtins import basestring
-ALL_OK = "spotseeker_server.auth.all_ok"
UW_SPOT_FORM = "spotseeker_server.org_forms.uw_spot.UWSpotForm"
UW_EXT_INFO_FORM = "spotseeker_server.org_forms.uw_spot.UWSpotExtendedInfoForm"
-@override_settings(SPOTSEEKER_AUTH_MODULE=ALL_OK)
+@override_settings(SPOTSEEKER_OAUTH_ENABLED=False)
@override_settings(SPOTSEEKER_SPOT_FORM=UW_SPOT_FORM)
@override_settings(SPOTSEEKER_SPOTEXTENDEDINFO_FORM=UW_EXT_INFO_FORM)
@override_settings(SPOTSEEKER_AUTH_ADMINS=("demo_user",))
@@ -188,103 +184,100 @@ def test_valid_json_outdated_etag(self):
)
def test_valid_json_but_invalid_extended_info(self):
- with self.settings(
- SPOTSEEKER_AUTH_MODULE=ALL_OK, SPOTSEEKER_SPOT_FORM=UW_SPOT_FORM
- ):
- c = Client()
- new_name = "testing PUT name: {0}".format(random.random())
- new_capacity = 20
-
- response = c.get(self.url)
- etag = response["ETag"]
- app_type = "food"
-
- json_string = (
- '{"name":"%s","capacity":"%s",\
- "location":{"latitude": 55, "longitude": -30},\
- "extended_info":{"location_description":\
- "This is a description",\
- "has_whiteboards":"true",\
- "num_computers": "10",\
- "has_outlets":"true","has_computers":"true",\
- "manager":"Sam","organization":"UW",\
- "app_type":"%s"}}'
- % (new_name, new_capacity, app_type)
- )
+ c = Client()
+ new_name = "testing PUT name: {0}".format(random.random())
+ new_capacity = 20
- response = c.put(
- self.url,
- json_string,
- content_type="application/json",
- If_Match=etag,
- )
- self.assertEquals(
- response.status_code, 200, "Accepts a valid json string"
- )
+ response = c.get(self.url)
+ etag = response["ETag"]
+ app_type = "food"
- # test: invalid extended info value
- response = c.get(self.url)
- etag = response["ETag"]
- updated_json_string = (
- '{"name":"%s","capacity":"%s",\
- "location": {"latitude": 55, "longitude": -30},\
- "extended_info":{"has_whiteboards":"true",\
- "location_description": " ",\
- "has_outlets":"wub wub wub wu wu wuhhhh WUB WUB WUBBBBUB", \
- "has_computers":"true", "num_computers":"10","manager":"Sam",\
- "organization":"UW"}}'
- % (new_name, new_capacity)
- )
+ json_string = (
+ '{"name":"%s","capacity":"%s",\
+ "location":{"latitude": 55, "longitude": -30},\
+ "extended_info":{"location_description":\
+ "This is a description",\
+ "has_whiteboards":"true",\
+ "num_computers": "10",\
+ "has_outlets":"true","has_computers":"true",\
+ "manager":"Sam","organization":"UW",\
+ "app_type":"%s"}}'
+ % (new_name, new_capacity, app_type)
+ )
- response = c.put(
- self.url,
- updated_json_string,
- content_type="application/json",
- If_Match=etag,
- )
- self.assertEquals(
- response.status_code,
- 400,
- "Doesn't update spot with invalid extended info",
- )
+ response = c.put(
+ self.url,
+ json_string,
+ content_type="application/json",
+ If_Match=etag,
+ )
+ self.assertEquals(
+ response.status_code, 200, "Accepts a valid json string"
+ )
- response = c.get(self.url)
- self.assertEquals(
- json.loads(json_string)["extended_info"],
- json.loads(response.content)["extended_info"],
- "Doesn't update spot with invalid extended info",
- )
+ # test: invalid extended info value
+ response = c.get(self.url)
+ etag = response["ETag"]
+ updated_json_string = (
+ '{"name":"%s","capacity":"%s",\
+ "location": {"latitude": 55, "longitude": -30},\
+ "extended_info":{"has_whiteboards":"true",\
+ "location_description": " ",\
+ "has_outlets":"wub wub wub wu wu wuhhhh WUB WUB WUBBBBUB", \
+ "has_computers":"true", "num_computers":"10","manager":"Sam",\
+ "organization":"UW"}}'
+ % (new_name, new_capacity)
+ )
- # test: invalid int value
- invalid_int = "invalid_int"
- invalid_int_json_string = (
- '{"name":"%s","capacity":"%s",\
- "location": {"latitude": 55, "longitude": -30},\
- "extended_info":{"has_whiteboards":"true",\
- "location_description": "This is a description",\
- "has_outlets":"true", "has_computers":"true", \
- "num_computers":"%s","manager":"Sam","organization":"UW"}}'
- % (new_name, new_capacity, invalid_int)
- )
+ response = c.put(
+ self.url,
+ updated_json_string,
+ content_type="application/json",
+ If_Match=etag,
+ )
+ self.assertEquals(
+ response.status_code,
+ 400,
+ "Doesn't update spot with invalid extended info",
+ )
- response = c.put(
- self.url,
- invalid_int_json_string,
- content_type="application/json",
- If_Match=etag,
- )
- self.assertEquals(
- response.status_code,
- 400,
- "Doesn't update spot with invalid int value",
- )
+ response = c.get(self.url)
+ self.assertEquals(
+ json.loads(json_string)["extended_info"],
+ json.loads(response.content)["extended_info"],
+ "Doesn't update spot with invalid extended info",
+ )
- response = c.get(self.url)
- self.assertEquals(
- json.loads(json_string)["extended_info"],
- json.loads(response.content)["extended_info"],
- "Doesn't update spot with invalid int value",
- )
+ # test: invalid int value
+ invalid_int = "invalid_int"
+ invalid_int_json_string = (
+ '{"name":"%s","capacity":"%s",\
+ "location": {"latitude": 55, "longitude": -30},\
+ "extended_info":{"has_whiteboards":"true",\
+ "location_description": "This is a description",\
+ "has_outlets":"true", "has_computers":"true", \
+ "num_computers":"%s","manager":"Sam","organization":"UW"}}'
+ % (new_name, new_capacity, invalid_int)
+ )
+
+ response = c.put(
+ self.url,
+ invalid_int_json_string,
+ content_type="application/json",
+ If_Match=etag,
+ )
+ self.assertEquals(
+ response.status_code,
+ 400,
+ "Doesn't update spot with invalid int value",
+ )
+
+ response = c.get(self.url)
+ self.assertEquals(
+ json.loads(json_string)["extended_info"],
+ json.loads(response.content)["extended_info"],
+ "Doesn't update spot with invalid int value",
+ )
def test_phone_number_validation(self):
phone_numbers = (
diff --git a/spotseeker_server/test/uw_spot/uw_search.py b/spotseeker_server/test/uw_spot/uw_search.py
index d60701c4..e4f64f4e 100644
--- a/spotseeker_server/test/uw_spot/uw_search.py
+++ b/spotseeker_server/test/uw_spot/uw_search.py
@@ -1,7 +1,6 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
-from django.conf import settings
from django.test import TestCase
from django.test.client import Client
from django.test.utils import override_settings
@@ -11,7 +10,7 @@
@override_settings(
- SPOTSEEKER_AUTH_MODULE="spotseeker_server.auth.all_ok",
+ SPOTSEEKER_OAUTH_ENABLED=False,
SPOTSEEKER_SEARCH_FILTERS=(
"spotseeker_server.org_filters.uw_search.Filter",
),
diff --git a/spotseeker_server/tests.py b/spotseeker_server/tests.py
index 257269e5..968f0b9d 100644
--- a/spotseeker_server/tests.py
+++ b/spotseeker_server/tests.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
# Use full test failure messages
@@ -14,15 +14,13 @@
from spotseeker_server.test.spot_get import SpotGETTest
from spotseeker_server.test.no_rest_methods import NoRESTMethodsTest
from spotseeker_server.test.schema import SpotSchemaTest
+from spotseeker_server.test.oauth import SpotAuthOAuth
from spotseeker_server.test.images.get import SpotImageGETTest
from spotseeker_server.test.images.post import SpotImagePOSTTest
from spotseeker_server.test.images.put import SpotImagePUTTest
from spotseeker_server.test.images.delete import SpotImageDELETETest
from spotseeker_server.test.images.thumb import ImageThumbTest
from spotseeker_server.test.images.spot_info import SpotResourceImageTest
-from spotseeker_server.test.images.oauth_spot_info import (
- SpotResourceOAuthImageTest,
-)
from spotseeker_server.test.item.model import ItemModelTest
from spotseeker_server.test.search.item import SpotSearchItemTest
from spotseeker_server.test.search.buildings import BuildingSearchTest
@@ -56,9 +54,6 @@
)
from spotseeker_server.test.hours.overlap import SpotHoursOverlapTest
from spotseeker_server.test.hours.modify import SpotHoursModifyTest
-from spotseeker_server.test.auth.all_ok import SpotAuthAllOK
-from spotseeker_server.test.auth.oauth import SpotAuthOAuth
-from spotseeker_server.test.auth.oauth_logger import SpotAuthOAuthLogger
from spotseeker_server.test.uw_spot.spot_form import UWSpotFormTest
from spotseeker_server.test.uw_spot.spot_post import UWSpotPOSTTest
from spotseeker_server.test.uw_spot.spot_put import UWSpotPUTTest
diff --git a/spotseeker_server/urls.py b/spotseeker_server/urls.py
index f461caa9..a514570e 100644
--- a/spotseeker_server/urls.py
+++ b/spotseeker_server/urls.py
@@ -1,15 +1,8 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
-""" Changes
- =================================================================
-
- sbutler1@illinois.edu: added external_id support; moved some URL
- patterns into the ThumbnailView; added names for reverse()
- support.
-"""
-
-from django.conf.urls import include, url
+from django.urls import path, re_path
+from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
from spotseeker_server.views.buildings import BuildingListView
from spotseeker_server.views.spot import SpotView
@@ -24,63 +17,123 @@
from spotseeker_server.views.item_image import ItemImageView
from spotseeker_server.views.add_item_image import AddItemImageView
from spotseeker_server.views.item_thumbnail import ItemThumbnailView
+import oauth2_provider.views as oauth2_views
+
+# OAuth2 provider endpoints
+oauth2_endpoint_views = [
+ path(
+ "authorize/",
+ oauth2_views.AuthorizationView.as_view(),
+ name="authorize"
+ ),
+ path("token/", oauth2_views.TokenView.as_view(), name="token"),
+ path(
+ "revoke-token/",
+ oauth2_views.RevokeTokenView.as_view(),
+ name="revoke-token"
+ ),
+]
+
+if settings.DEBUG:
+ # OAuth2 Application Management endpoints
+ oauth2_endpoint_views += [
+ path(
+ "applications/",
+ oauth2_views.ApplicationList.as_view(),
+ name="list"
+ ),
+ path(
+ "applications/register/",
+ oauth2_views.ApplicationRegistration.as_view(),
+ name="register"
+ ),
+ path(
+ "applications//",
+ oauth2_views.ApplicationDetail.as_view(),
+ name="detail"
+ ),
+ path(
+ "applications//delete/",
+ oauth2_views.ApplicationDelete.as_view(),
+ name="delete"
+ ),
+ path(
+ "applications//update/",
+ oauth2_views.ApplicationUpdate.as_view(),
+ name="update"
+ ),
+ ]
+
+ # OAuth2 Token Management endpoints
+ oauth2_endpoint_views += [
+ path(
+ "authorized-tokens/",
+ oauth2_views.AuthorizedTokensListView.as_view(),
+ name="authorized-token-list"
+ ),
+ path(
+ "authorized-tokens//delete/",
+ oauth2_views.AuthorizedTokenDeleteView.as_view(),
+ name="authorized-token-delete"
+ ),
+ ]
urlpatterns = [
- url(r"v1/null$", csrf_exempt(NullView().run)),
- url(
+ path("v1/null", csrf_exempt(NullView().run)),
+ re_path(
r"v1/spot/(?P(\d+|external:[\w-]+))$",
csrf_exempt(SpotView().run),
name="spot",
),
- url(r"v1/spot/?$", csrf_exempt(SearchView().run), name="spot-search"),
- url(r"v1/spot/all$", csrf_exempt(AllSpotsView().run), name="spots"),
- url(
+ re_path(r"v1/spot/?$", csrf_exempt(SearchView().run), name="spot-search"),
+ path("v1/spot/all", csrf_exempt(AllSpotsView().run), name="spots"),
+ re_path(
r"v1/buildings/?$",
csrf_exempt(BuildingListView().run),
name="buildings",
),
- url(r"v1/schema$", csrf_exempt(SchemaGenView().run), name="schema"),
- url(r"v1/spot/(?P\d+)/image$", csrf_exempt(AddImageView().run)),
- url(
- r"v1/spot/(?P\d+)/image/" r"(?P\d+)$",
+ path("v1/schema", csrf_exempt(SchemaGenView().run), name="schema"),
+ path(r"v1/spot//image", csrf_exempt(AddImageView().run)),
+ path(
+ "v1/spot//image/",
csrf_exempt(ImageView().run),
name="spot-image",
),
- url(
+ re_path(
r"v1/spot/(?P\d+)/image/"
r"(?P\d+)/thumb/constrain/"
"(?P.+)?$",
csrf_exempt(ThumbnailView().run),
{"constrain": True},
),
- url(
+ re_path(
r"v1/spot/(?P\d+)/image/"
r"(?P\d+)/thumb/"
r"(?P.+)?$",
csrf_exempt(ThumbnailView().run),
name="spot-image-thumb",
),
- url(
+ re_path(
r"v1/item/(?P\d+)/image$", csrf_exempt(AddItemImageView().run)
),
- url(
+ re_path(
r"v1/item/(?P\d+)/image/" r"(?P[\d]+)$",
csrf_exempt(ItemImageView().run),
name="item-image",
),
- url(
+ re_path(
r"v1/item/(?P\d+)/image/"
r"(?P\d+)/thumb/constrain/"
r"(?P.+)?$",
csrf_exempt(ItemThumbnailView().run),
{"constrain": True},
),
- url(
+ re_path(
r"v1/item/(?P\d+)/image/"
r"(?P\d+)/thumb/"
r"(?P.+)?$",
csrf_exempt(ItemThumbnailView().run),
name="item-image-thumb",
),
- url(r"v1/user/me$", csrf_exempt(PersonView().run)),
+ re_path(r"v1/user/me$", csrf_exempt(PersonView().run)),
]
diff --git a/spotseeker_server/views/add_image.py b/spotseeker_server/views/add_image.py
index b60091d3..177e508e 100644
--- a/spotseeker_server/views/add_image.py
+++ b/spotseeker_server/views/add_image.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -10,18 +10,16 @@
from spotseeker_server.views.rest_dispatch import RESTDispatch, RESTException
from spotseeker_server.models import SpotImage, Spot
from django.http import HttpResponse
-from spotseeker_server.require_auth import *
from PIL import Image
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
-class AddImageView(RESTDispatch):
+class AddImageView(RESTDispatch, ReadWriteScopedResourceView):
"""Saves a SpotImage for a particular Spot on POST to
/api/v1/spot//image.
"""
- @user_auth_required
- @admin_auth_required
- def POST(self, request, spot_id):
+ def post(self, request, spot_id):
spot = Spot.objects.get(pk=spot_id)
if "image" not in request.FILES:
diff --git a/spotseeker_server/views/add_item_image.py b/spotseeker_server/views/add_item_image.py
index 3dbaa3d8..8f3fd9b7 100644
--- a/spotseeker_server/views/add_item_image.py
+++ b/spotseeker_server/views/add_item_image.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -10,18 +10,16 @@
from spotseeker_server.views.rest_dispatch import RESTDispatch, RESTException
from spotseeker_server.models import ItemImage, Item
from django.http import HttpResponse
-from spotseeker_server.require_auth import *
from PIL import Image
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
-class AddItemImageView(RESTDispatch):
+class AddItemImageView(RESTDispatch, ReadWriteScopedResourceView):
"""Saves a ItemImage for a particular Item on POST to
/api/v1/item/
- /image.
"""
- @user_auth_required
- @admin_auth_required
- def POST(self, request, item_id):
+ def post(self, request, item_id):
item = Item.objects.get(pk=item_id)
if "image" not in request.FILES:
diff --git a/spotseeker_server/views/all_spots.py b/spotseeker_server/views/all_spots.py
index 0633a302..69fad325 100644
--- a/spotseeker_server/views/all_spots.py
+++ b/spotseeker_server/views/all_spots.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -9,11 +9,10 @@
from spotseeker_server.views.rest_dispatch import RESTDispatch, JSONResponse
from spotseeker_server.models import Spot
-from spotseeker_server.require_auth import app_auth_required
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
-class AllSpotsView(RESTDispatch):
- @app_auth_required
- def GET(self, request):
+class AllSpotsView(RESTDispatch, ReadWriteScopedResourceView):
+ def get(self, request):
spots = [spot.json_data_structure() for spot in Spot.objects.all()]
return JSONResponse(spots)
diff --git a/spotseeker_server/views/buildings.py b/spotseeker_server/views/buildings.py
index 7f5f75cb..7ef0f463 100644
--- a/spotseeker_server/views/buildings.py
+++ b/spotseeker_server/views/buildings.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -9,21 +9,20 @@
"""
from spotseeker_server.views.rest_dispatch import RESTDispatch, JSONResponse
-from spotseeker_server.require_auth import *
from spotseeker_server.models import Spot
from spotseeker_server.org_filters import SearchFilterChain
from spotseeker_server.views.search import SearchView
from django.http import HttpResponse
from django.core.exceptions import FieldError
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
-class BuildingListView(RESTDispatch):
+class BuildingListView(RESTDispatch, ReadWriteScopedResourceView):
"""Performs actions on the list of buildings, at /api/v1/buildings.
GET returns 200 with a list of buildings.
"""
- @app_auth_required
- def GET(self, request):
+ def get(self, request):
chain = SearchFilterChain(request)
search_view = SearchView()
spots = SearchView.filter_on_request(
diff --git a/spotseeker_server/views/image.py b/spotseeker_server/views/image.py
index 31419c88..53cb7ffe 100644
--- a/spotseeker_server/views/image.py
+++ b/spotseeker_server/views/image.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -18,19 +18,18 @@
from wsgiref.util import FileWrapper
from django.core.exceptions import ValidationError
from django.core.files.images import ImageFile
-from spotseeker_server.require_auth import *
from spotseeker_server.models import *
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
-class ImageView(RESTDispatch):
+class ImageView(RESTDispatch, ReadWriteScopedResourceView):
"""Handles actions at /api/v1/spot//image/.
GET returns 200 with the image.
PUT returns 200 and updates the image.
DELETE returns 200 and deletes the image.
"""
- @app_auth_required
- def GET(self, request, spot_id, image_id):
+ def get(self, request, spot_id, image_id):
img = SpotImage.objects.get(pk=image_id)
spot = img.spot
@@ -48,9 +47,7 @@ def GET(self, request, spot_id, image_id):
response["Content-type"] = img.content_type
return response
- @user_auth_required
- @admin_auth_required
- def PUT(self, request, spot_id, image_id):
+ def put(self, request, spot_id, image_id):
img = SpotImage.objects.get(pk=image_id)
spot = img.spot
@@ -73,11 +70,9 @@ def PUT(self, request, spot_id, image_id):
img.display_index = request.META["files"]["display_index"]
img.save()
- return self.GET(request, spot_id, image_id)
+ return self.get(request, spot_id, image_id)
- @user_auth_required
- @admin_auth_required
- def DELETE(self, request, spot_id, image_id):
+ def delete(self, request, spot_id, image_id):
img = SpotImage.objects.get(pk=image_id)
spot = img.spot
diff --git a/spotseeker_server/views/item_image.py b/spotseeker_server/views/item_image.py
index abdbd4f9..f192327f 100644
--- a/spotseeker_server/views/item_image.py
+++ b/spotseeker_server/views/item_image.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -18,19 +18,18 @@
from wsgiref.util import FileWrapper
from django.core.exceptions import ValidationError
from django.core.files.images import ImageFile
-from spotseeker_server.require_auth import *
from spotseeker_server.models import *
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
-class ItemImageView(RESTDispatch):
+class ItemImageView(RESTDispatch, ReadWriteScopedResourceView):
"""Handles actions at /api/v1/item/
- /image/.
GET returns 200 with the image.
PUT returns 200 and updates the image.
DELETE returns 200 and deletes the image.
"""
- @app_auth_required
- def GET(self, request, item_id, image_id):
+ def get(self, request, item_id, image_id):
img = ItemImage.objects.get(pk=image_id)
item = img.item
@@ -48,9 +47,7 @@ def GET(self, request, item_id, image_id):
response["Content-type"] = img.content_type
return response
- @user_auth_required
- @admin_auth_required
- def PUT(self, request, item_id, image_id):
+ def put(self, request, item_id, image_id):
img = ItemImage.objects.get(pk=image_id)
item = img.item
@@ -74,11 +71,9 @@ def PUT(self, request, item_id, image_id):
img.save()
item.spot.save()
- return self.GET(request, item_id, image_id)
+ return self.get(request, item_id, image_id)
- @user_auth_required
- @admin_auth_required
- def DELETE(self, request, item_id, image_id):
+ def delete(self, request, item_id, image_id):
img = ItemImage.objects.get(pk=image_id)
item = img.item
diff --git a/spotseeker_server/views/item_thumbnail.py b/spotseeker_server/views/item_thumbnail.py
index 5b545646..a11e6717 100644
--- a/spotseeker_server/views/item_thumbnail.py
+++ b/spotseeker_server/views/item_thumbnail.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -8,37 +8,27 @@
here to simplify the URL patterns; adapt to the new RESTDispatch
framework.
"""
-try:
- from cStringIO import StringIO as IOStream
-except ModuleNotFoundError:
- from io import BytesIO as IOStream
+from io import BytesIO as IOStream
from spotseeker_server.views.rest_dispatch import RESTDispatch, RESTException
from spotseeker_server.models import ItemImage, Item
from django.http import HttpResponse
from django.utils.http import http_date
-from spotseeker_server.require_auth import app_auth_required
from PIL import Image
import time
import re
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
RE_WIDTH = re.compile(r"width:(\d+)")
RE_HEIGHT = re.compile(r"height:(\d+)")
RE_WIDTHxHEIGHT = re.compile(r"^(\d+)x(\d+)$")
-class ItemThumbnailView(RESTDispatch):
+class ItemThumbnailView(RESTDispatch, ReadWriteScopedResourceView):
"""Returns 200 with a thumbnail of a ItemImage."""
- @app_auth_required
- def GET(
- self,
- request,
- item_id,
- image_id,
- thumb_dimensions=None,
- constrain=False,
- ):
+ def get(self, request, item_id, image_id,
+ thumb_dimensions=None, constrain=False):
img = ItemImage.objects.get(pk=image_id)
item = img.item
diff --git a/spotseeker_server/views/null.py b/spotseeker_server/views/null.py
index 03a065f1..23423700 100644
--- a/spotseeker_server/views/null.py
+++ b/spotseeker_server/views/null.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" This class is just here to help with testing coverage
diff --git a/spotseeker_server/views/oauth.py b/spotseeker_server/views/oauth.py
deleted file mode 100644
index 594daef2..00000000
--- a/spotseeker_server/views/oauth.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2023 UW-IT, University of Washington
-# SPDX-License-Identifier: Apache-2.0
-
-from django.http import HttpResponse
-from django.shortcuts import render_to_response
-from django.template import RequestContext
-from oauth_provider.models import Token
-from spotseeker_server.models import TrustedOAuthClient
-
-
-def authorize(request, token, callback, params):
- consumer = token.consumer
-
- bypasses_auth = False
- trusted_client = TrustedOAuthClient.objects.filter(consumer=consumer)
- if len(trusted_client) and trusted_client[0].bypasses_user_authorization:
- bypasses_auth = True
-
- request.session["oauth"] = token.key
- return render_to_response(
- "oauth/authorize.html",
- {
- "consumer": consumer.name,
- "token": request.GET["oauth_token"],
- "bypass_auth": bypasses_auth,
- },
- RequestContext(request),
- )
-
-
-def callback(request, **kwargs):
- if "oauth_token" not in kwargs:
- return render_to_response("oauth/declined.html")
-
- token = Token.objects.get(key=kwargs["oauth_token"])
-
- return render_to_response(
- "oauth/oob.html",
- {
- "verifier": token.verifier,
- },
- RequestContext(request),
- )
diff --git a/spotseeker_server/views/person.py b/spotseeker_server/views/person.py
index bb27a2f9..a0f38bbc 100644
--- a/spotseeker_server/views/person.py
+++ b/spotseeker_server/views/person.py
@@ -1,16 +1,15 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from spotseeker_server.views.rest_dispatch import RESTDispatch, JSONResponse
-from spotseeker_server.require_auth import user_auth_required
from django.conf import settings
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
-class PersonView(RESTDispatch):
+class PersonView(RESTDispatch, ReadWriteScopedResourceView):
"""Information (username, email) about a person"""
- @user_auth_required
- def GET(self, request):
+ def get(self, request):
user = self._get_user(request)
data = {
diff --git a/spotseeker_server/views/rest_dispatch.py b/spotseeker_server/views/rest_dispatch.py
index 7097ed46..cf46fdb1 100644
--- a/spotseeker_server/views/rest_dispatch.py
+++ b/spotseeker_server/views/rest_dispatch.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -15,8 +15,15 @@
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.conf import settings
from django.http import HttpResponse
+from oauth2_provider.models import get_access_token_model
import simplejson as json
import traceback
+import logging
+
+
+logger = logging.getLogger(__name__)
+
+AccessToken = get_access_token_model()
class JSONResponse(HttpResponse):
@@ -69,14 +76,17 @@ def run(self, *args, **named_args):
method = request.META["REQUEST_METHOD"]
try:
- if "GET" == method and hasattr(self, "GET"):
- response = self.GET(*args, **named_args)
- elif "POST" == method and hasattr(self, "POST"):
- response = self.POST(*args, **named_args)
- elif "PUT" == method and hasattr(self, "PUT"):
- response = self.PUT(*args, **named_args)
- elif "DELETE" == method and hasattr(self, "DELETE"):
- response = self.DELETE(*args, **named_args)
+ if settings.SPOTSEEKER_OAUTH_ENABLED:
+ self.validate_oauth_scope(request, method)
+
+ if "GET" == method and hasattr(self, "get"):
+ response = self.get(*args, **named_args)
+ elif "POST" == method and hasattr(self, "post"):
+ response = self.post(*args, **named_args)
+ elif "PUT" == method and hasattr(self, "put"):
+ response = self.put(*args, **named_args)
+ elif "DELETE" == method and hasattr(self, "delete"):
+ response = self.delete(*args, **named_args)
else:
raise RESTException("Method not allowed", 405)
@@ -121,9 +131,36 @@ def validate_etag(self, request, obj):
if request.META["HTTP_IF_MATCH"] != obj.etag:
raise RESTException("Invalid ETag", 409)
+ def validate_oauth_scope(self, request, method: str) -> None:
+ if "Authorization" not in request.headers:
+ raise RESTException("Missing Authorization header", 401)
+
+ access_token = request.headers.get("Authorization").split(" ")[1]
+
+ try:
+ token = AccessToken.objects.get(token=access_token)
+
+ if token.is_expired():
+ raise RESTException("Expired access token", 401)
+
+ except AccessToken.DoesNotExist:
+ raise RESTException("Invalid access token", 401)
+
+ scope = token.scope
+ logger.debug(f"Validating scope: {scope}")
+
+ # match scope with request method
+ if method == "GET":
+ if "read" not in scope:
+ raise RESTException(f"Invalid scope for method {method}", 403)
+ elif method in ("POST", "PUT", "DELETE"):
+ if "write" not in scope:
+ raise RESTException(f"Invalid scope for method {method}", 403)
+ else:
+ raise RESTException("Method not allowed", 405)
+
def _get_user(self, request):
if "SS_OAUTH_USER" not in request.META:
- print(request.META)
raise RESTException(
"missing oauth user - improper auth backend?", 400
)
diff --git a/spotseeker_server/views/schema_gen.py b/spotseeker_server/views/schema_gen.py
index 2240f51e..f6f733ca 100644
--- a/spotseeker_server/views/schema_gen.py
+++ b/spotseeker_server/views/schema_gen.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -10,17 +10,15 @@
from django.apps import apps
from django.core.exceptions import ImproperlyConfigured
-from django.http import HttpResponse
from spotseeker_server.forms.spot import SpotForm
from spotseeker_server.models import *
-from spotseeker_server.require_auth import *
from spotseeker_server.views.rest_dispatch import JSONResponse, RESTDispatch
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
-class SchemaGenView(RESTDispatch):
- @app_auth_required
- def GET(self, request):
+class SchemaGenView(RESTDispatch, ReadWriteScopedResourceView):
+ def get(self, request):
"""Json data that should contain every single piece of information
that any spot might contain.
diff --git a/spotseeker_server/views/search.py b/spotseeker_server/views/search.py
index 3c440e11..e9364361 100644
--- a/spotseeker_server/views/search.py
+++ b/spotseeker_server/views/search.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -23,7 +23,6 @@
from django.http import HttpResponse, HttpResponseBadRequest
from django.db.models import Q
from django.utils.datastructures import MultiValueDictKeyError
-from spotseeker_server.require_auth import *
from spotseeker_server.models import Spot, SpotType
from pyproj import Geod
from decimal import *
@@ -31,20 +30,18 @@
from datetime import datetime
import pytz
import sys
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
-class SearchView(RESTDispatch):
+class SearchView(RESTDispatch, ReadWriteScopedResourceView):
"""Handles searching for Spots with particular attributes
based on a query string.
"""
- @user_auth_required
- @admin_auth_required
- def POST(self, request):
+ def post(self, request):
return SpotView().run(request)
- @app_auth_required
- def GET(self, request):
+ def get(self, request):
chain = SearchFilterChain(request)
spots = self.filter_on_request(
request.GET, chain, request.META, "spot"
diff --git a/spotseeker_server/views/spot.py b/spotseeker_server/views/spot.py
index cca19a2d..a2f1d2a9 100644
--- a/spotseeker_server/views/spot.py
+++ b/spotseeker_server/views/spot.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -16,14 +16,13 @@
RESTFormInvalidError,
JSONResponse,
)
+
+# ItemStash import required for Signal receivers, do not remove!
+from spotseeker_server.views.spot_item import ItemStash
+
from spotseeker_server.forms.spot import SpotForm, SpotExtendedInfoForm
-from spotseeker_server.default_forms.item import DefaultItemForm as ItemForm
-from spotseeker_server.default_forms.item import (
- DefaultItemExtendedInfoForm as ItemExtendedInfoForm,
-)
from spotseeker_server.models import *
from django.http import HttpResponse
-from spotseeker_server.require_auth import *
from django.db import transaction
import simplejson as json
import django.dispatch
@@ -33,7 +32,7 @@
spot_post_save,
spot_post_build,
)
-import spotseeker_server.views.spot_item
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
from past.builtins import basestring
@@ -159,7 +158,7 @@ def _save_extended_info(sender, **kwargs):
pass
-class SpotView(RESTDispatch):
+class SpotView(RESTDispatch, ReadWriteScopedResourceView):
"""Performs actions on a Spot at /api/v1/spot/.
GET returns 200 with Spot details.
POST to /api/v1/spot with valid JSON returns 200 and creates a new Spot.
@@ -167,30 +166,23 @@ class SpotView(RESTDispatch):
DELETE returns 200 and deletes the Spot.
"""
- @app_auth_required
- def GET(self, request, spot_id):
+ def get(self, request, spot_id):
spot = Spot.get_with_external(spot_id)
response = JSONResponse(spot.json_data_structure())
response["ETag"] = spot.etag
return response
- @user_auth_required
- @admin_auth_required
- def POST(self, request):
+ def post(self, request):
return self.build_and_save_from_input(request, None)
- @user_auth_required
- @admin_auth_required
- def PUT(self, request, spot_id):
+ def put(self, request, spot_id):
spot = Spot.get_with_external(spot_id)
self.validate_etag(request, spot)
return self.build_and_save_from_input(request, spot)
- @user_auth_required
- @admin_auth_required
- def DELETE(self, request, spot_id):
+ def delete(self, request, spot_id):
spot = Spot.get_with_external(spot_id)
self.validate_etag(request, spot)
@@ -234,7 +226,7 @@ def build_and_save_from_input(self, request, spot):
stash=stash,
)
- # Remve excluded fields
+ # Remove excluded fields
excludefields = set(SpotForm.implementation().Meta.exclude)
for fieldname in excludefields:
if fieldname in json_values:
diff --git a/spotseeker_server/views/spot_item.py b/spotseeker_server/views/spot_item.py
index 4d3445fa..7fdd8b4e 100644
--- a/spotseeker_server/views/spot_item.py
+++ b/spotseeker_server/views/spot_item.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
from django import forms
@@ -14,10 +14,6 @@
DefaultItemExtendedInfoForm as ItemExtendedInfoForm,
)
from spotseeker_server.models import *
-from django.http import HttpResponse
-from spotseeker_server.require_auth import *
-from django.db import transaction
-import simplejson as json
import django.dispatch
from spotseeker_server.dispatch import (
spot_pre_build,
diff --git a/spotseeker_server/views/thumbnail.py b/spotseeker_server/views/thumbnail.py
index b1132276..9d95bedb 100644
--- a/spotseeker_server/views/thumbnail.py
+++ b/spotseeker_server/views/thumbnail.py
@@ -1,4 +1,4 @@
-# Copyright 2023 UW-IT, University of Washington
+# Copyright 2024 UW-IT, University of Washington
# SPDX-License-Identifier: Apache-2.0
""" Changes
@@ -17,28 +17,21 @@
from spotseeker_server.models import SpotImage, Spot
from django.http import HttpResponse
from django.utils.http import http_date
-from spotseeker_server.require_auth import app_auth_required
from PIL import Image
import time
import re
+from oauth2_provider.views.generic import ReadWriteScopedResourceView
RE_WIDTH = re.compile(r"width:(\d+)")
RE_HEIGHT = re.compile(r"height:(\d+)")
RE_WIDTHxHEIGHT = re.compile(r"^(\d+)x(\d+)$")
-class ThumbnailView(RESTDispatch):
+class ThumbnailView(RESTDispatch, ReadWriteScopedResourceView):
"""Returns 200 with a thumbnail of a SpotImage."""
- @app_auth_required
- def GET(
- self,
- request,
- spot_id,
- image_id,
- thumb_dimensions=None,
- constrain=False,
- ):
+ def get(self, request, spot_id, image_id,
+ thumb_dimensions=None, constrain=False):
img = SpotImage.objects.get(pk=image_id)
spot = img.spot