diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 7169f1c1..34f3ca5c 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -49,14 +49,8 @@ production docker compose file to collect the static files 7. Run `docker compose -f ./prod/docker-compose.prod.yml up` to start the server add `-d` for a silent version to run in the background -8. **OPTIONAL** Change the `APPLICATION_CLIENT_ID` and the `VITE_APP_OAUTH_CLIENT_ID` in - the `./prod/env.production` to a custom ID - this will - probably require a `docker compose -f ./prod/docker-compose.prod.yml build` \ - to build the app afterwards. This Id is used to indetify the application and - isn't required to be changed especially if the building of the client is done - outside of deployment. -9. After creating the basic application log into the django admin `batdetectai.kitware.com/admin` -10. Test logging in/out and uploading data to the server. +8. After creating the basic application log into the django admin `batdetectai.kitware.com/admin` +9. Test logging in/out and uploading data to the server. ### GRTS Cell Id support @@ -126,7 +120,6 @@ for a list of environment variables that you'll need to populate for your deploy - `DJANGO_CELERY_BROKER_URL` is used to make sure django can send tasks to the `celery` service. For example, if using [RabbitMQ](https://www.rabbitmq.com/), it might look like this: `amqp://rabbitmq:5672` - `AWS_*` and `DJANGO_STORAGE_BUCKET_NAME` are used to make sure the application can connect to your S3 bucket -- `APPLICATION_CLIENT_ID`: This is used to register the front-end Vue single-page app as an Oauth application. - `NABAT_API_URL`: the location of the NABat GraphQL endpoint used to retrieve information about files in NABat. - `VITE_APP_API_ROUTE`: this tells the Vue application where the backend (Django) API can be found. - `DJANGO_BATAI_URL_PATH`: this allows the Django application to be mounted at a subpath in a URL. diff --git a/bats_ai/core/management/commands/makeclient.py b/bats_ai/core/management/commands/makeclient.py deleted file mode 100644 index 3a5edfa7..00000000 --- a/bats_ai/core/management/commands/makeclient.py +++ /dev/null @@ -1,55 +0,0 @@ -import os - -from django.contrib.auth.models import User -import djclick as click -from oauth2_provider.models import Application - -CLIENT_ID = os.environ.get('APPLICATION_CLIENT_ID', 'HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP') - - -# create django oauth toolkit appliction (client) -@click.option( - '--username', - type=click.STRING, - required=True, - help='superuser username for application creator', -) -@click.option( - '--uri', - type=click.STRING, - default='http://localhost:3000/', - required=False, - help='redirect uri for application', -) -@click.option( - '--clientid', - type=click.STRING, - default=CLIENT_ID, - required=False, - help='clientID used in the application', -) -@click.command() -def command(username, uri, clientid): - if Application.objects.filter(client_id=clientid).exists(): - click.echo('The client already exists. You can administer it from the admin console.') - return - - if username: - user = User.objects.get(username=username) - else: - first_user = User.objects.first() - if first_user: - user = first_user - - if user: - application = Application( - name='batsai-client', - client_id=clientid, - client_secret='', - client_type='public', - redirect_uris=uri, - authorization_grant_type='authorization-code', - user=user, - skip_authorization=True, - ) - application.save() diff --git a/bats_ai/core/migrations/0001_default_site.py b/bats_ai/core/migrations/0001_default_site.py new file mode 100644 index 00000000..11f9174c --- /dev/null +++ b/bats_ai/core/migrations/0001_default_site.py @@ -0,0 +1,40 @@ +from django.conf import settings +from django.db import migrations +from django.db.backends.base.schema import BaseDatabaseSchemaEditor +from django.db.migrations.state import StateApps + + +def update_default_site(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: + Site = apps.get_model('sites', 'Site') # noqa: N806 + + # A default site object may or may not exist. + # If this is a brand-new database, the post_migrate will not fire until the very end of the + # "migrate" command, so the sites app will not have created a default site object yet. + # If this is an existing database, the sites app will likely have created an default site + # object already. + Site.objects.update_or_create( + pk=settings.SITE_ID, + defaults={ + 'domain': 'api.bateval.com', + 'name': 'bats-ai', + }, + ) + + +def rollback_default_site(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: + Site = apps.get_model('sites', 'Site') # noqa: N806 + + # This is the initial value of the default site object, as populated by the sites app. + # If it doesn't exist for some reason, there is nothing to roll back. + Site.objects.filter(pk=settings.SITE_ID).update(domain='example.com', name='example.com') + + +class Migration(migrations.Migration): + dependencies = [ + # This is the final sites app migration + ('sites', '0002_alter_domain_unique'), + ] + + operations = [ + migrations.RunPython(update_default_site, rollback_default_site, elidable=False), + ] diff --git a/bats_ai/core/migrations/0002_oauth_application.py b/bats_ai/core/migrations/0002_oauth_application.py new file mode 100644 index 00000000..2a053434 --- /dev/null +++ b/bats_ai/core/migrations/0002_oauth_application.py @@ -0,0 +1,42 @@ +from django.db import migrations +from django.db.backends.base.schema import BaseDatabaseSchemaEditor +from django.db.migrations.state import StateApps + +APPLICATION_NAME = 'batsai-client' +CLIENT_ID = 'HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP' + + +def create_oauth2_application(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: + Application = apps.get_model('oauth2_provider', 'Application') # noqa: N806 + + Application.objects.create( + name=APPLICATION_NAME, + client_id=CLIENT_ID, + user=None, + redirect_uris='http://localhost:8080/', + client_type='public', + authorization_grant_type='authorization-code', + # Trust our own client, so don't require users to consent. + skip_authorization=True, + client_secret='', + # No need to set "allowed_origins", we provide CORS via "django-cors-headers". + # No need to set "post_logout_redirect_uris", we don't use RP-initiated logout. + ) + + +def delete_oauth2_application(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None: + Application = apps.get_model('oauth2_provider', 'Application') # noqa: N806 + + Application.objects.filter(name=APPLICATION_NAME).delete() + + +class Migration(migrations.Migration): + dependencies = [ + ('core', '0001_default_site'), + # This is the final oauth2_provider app migration + ('oauth2_provider', '0010_application_allowed_origins'), + ] + + operations = [ + migrations.RunPython(create_oauth2_application, delete_oauth2_application), + ] diff --git a/bats_ai/core/migrations/0026_merge.py b/bats_ai/core/migrations/0026_merge.py new file mode 100644 index 00000000..b266027a --- /dev/null +++ b/bats_ai/core/migrations/0026_merge.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ('core', '0002_oauth_application'), + ('core', '0025_configuration_mark_annotations_completed_enabled_and_more'), + ] diff --git a/client/src/plugins/Oauth.ts b/client/src/plugins/Oauth.ts index aaa6daae..7c4281bb 100644 --- a/client/src/plugins/Oauth.ts +++ b/client/src/plugins/Oauth.ts @@ -1,10 +1,11 @@ import OauthClient from '@resonant/oauth-client'; import { ref } from 'vue'; +const CLIENT_ID = 'HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP'; + const redirectUrl = new URL((import.meta.env.VITE_APP_LOGIN_REDIRECT || location.origin) as string); const baseUrl = new URL(import.meta.env.VITE_APP_OAUTH_API_ROOT as string); -const clientId = import.meta.env.VITE_APP_OAUTH_CLIENT_ID as string; -const oauthClient = new OauthClient(baseUrl, clientId, { redirectUrl }); +const oauthClient = new OauthClient(baseUrl, CLIENT_ID, { redirectUrl }); export const loggedIn = ref(oauthClient.isLoggedIn); @@ -18,4 +19,4 @@ export async function maybeRestoreLogin() { loggedIn.value = oauthClient.isLoggedIn; } -export default oauthClient; \ No newline at end of file +export default oauthClient; diff --git a/dev/.env.docker-compose b/dev/.env.docker-compose index 05a17764..2d019fbb 100644 --- a/dev/.env.docker-compose +++ b/dev/.env.docker-compose @@ -12,9 +12,7 @@ DJANGO_INTERNAL_IPS=0.0.0.0/0 SERVERHOSTNAME=localhost -APPLICATION_CLIENT_ID=HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP # Application Identification NABAT_API_URL=https://api.sciencebase.gov/nabat-graphql/graphql VITE_APP_API_ROOT=http://localhost:8000/api/v1 VITE_APP_OAUTH_API_ROOT=http://localhost:8000/oauth/ -VITE_APP_OAUTH_CLIENT_ID=HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP VITE_APP_LOGIN_REDIRECT=http://localhost:3000 diff --git a/dev/.env.docker-compose-native b/dev/.env.docker-compose-native index fb081981..ba34c7bc 100644 --- a/dev/.env.docker-compose-native +++ b/dev/.env.docker-compose-native @@ -5,9 +5,7 @@ DJANGO_MINIO_STORAGE_URL=http://minioAccessKey:minioSecretKey@localhost:9000/dja SERVERHOSTNAME=localhost -APPLICATION_CLIENT_ID=HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP # Application Identification NABAT_API_URL=https://api.sciencebase.gov/nabat-graphql/graphql VITE_APP_API_ROOT=http://localhost:8000/api/v1 VITE_APP_OAUTH_API_ROOT=http://localhost:8000/oauth/ -VITE_APP_OAUTH_CLIENT_ID=HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP VITE_APP_LOGIN_REDIRECT=http://localhost:3000 diff --git a/prod/.env.kitware-production.template b/prod/.env.kitware-production.template index 8aaf3b36..cfb15f5f 100644 --- a/prod/.env.kitware-production.template +++ b/prod/.env.kitware-production.template @@ -29,11 +29,9 @@ DJANGO_DEFAULT_FROM_EMAIL SERVERHOSTNAME=batdetectai.kitware.com # Client -APPLICATION_CLIENT_ID=HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP # Application Identification NABAT_API_URL=https://api.sciencebase.gov/nabat-graphql/graphql VITE_APP_API_ROOT=https://batdetectai.kitware.com/api/v1 VITE_APP_OAUTH_API_ROOT=https://batdetectai.kitware.com/oauth/ -VITE_APP_OAUTH_CLIENT_ID=HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP VITE_APP_LOGIN_REDIRECT=https://batdetectai.kitware.com # nginx/traefik diff --git a/prod/.env.nabat-production.template b/prod/.env.nabat-production.template index 99b6cc56..b6b33f88 100644 --- a/prod/.env.nabat-production.template +++ b/prod/.env.nabat-production.template @@ -33,9 +33,7 @@ DJANGO_BATAI_URL_PATH= SERVERHOSTNAME=batdetectai.kitware.com # Client Environment Variables -APPLICATION_CLIENT_ID=HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP # Application Identification NABAT_API_URL=https://api.sciencebase.gov/nabat-graphql/graphql VITE_APP_API_ROOT=https://batdetectai.kitware.com/api/v1 VITE_APP_OAUTH_API_ROOT=https://batdetectai.kitware.com/oauth/ -VITE_APP_OAUTH_CLIENT_ID=HSJWFZ2cIpWQOvNyCXyStV9hiOd7DfWeBOCzo4pP VITE_APP_LOGIN_REDIRECT=https://batdetectai.kitware.com diff --git a/prod/NABat-Deploy.md b/prod/NABat-Deploy.md index 5ec66583..745de9fc 100644 --- a/prod/NABat-Deploy.md +++ b/prod/NABat-Deploy.md @@ -12,7 +12,6 @@ docker build\ --build-arg DJANGO_BATAI_URL_PATH=${DJANGO_BATAI_URL_PATH}\ --build-arg VITE_APP_API_ROOT=${VITE_APP_API_ROOT}\ --build-arg VITE_APP_OAUTH_API_ROOT=${VITE_APP_OAUTH_API_ROOT}\ - --build-arg VITE_APP_OAUTH_CLIENT_ID=${VITE_APP_OAUTH_CLIENT_ID}\ --build-arg VITE_APP_LOGIN_REDIRECT=${VITE_APP_LOGIN_REDIRECT}\ -t ${AWS_IMAGE_LATEST}\ --pull -f ${DOCKER_FILE_LOCATION} . diff --git a/prod/client.Dockerfile b/prod/client.Dockerfile index fd3358f6..06b5715b 100644 --- a/prod/client.Dockerfile +++ b/prod/client.Dockerfile @@ -6,7 +6,6 @@ FROM node:lts-alpine AS build-stage # Build-time args ARG VITE_APP_API_ROOT ARG VITE_APP_OAUTH_API_ROOT -ARG VITE_APP_OAUTH_CLIENT_ID ARG VITE_APP_LOGIN_REDIRECT ARG DJANGO_BATAI_URL_PATH ARG DJANGO_MINIO_STORAGE_URL @@ -14,7 +13,6 @@ ARG DJANGO_MINIO_STORAGE_URL # Set environment for build ENV VITE_APP_API_ROOT=${VITE_APP_API_ROOT} ENV VITE_APP_OAUTH_API_ROOT=${VITE_APP_OAUTH_API_ROOT} -ENV VITE_APP_OAUTH_CLIENT_ID=${VITE_APP_OAUTH_CLIENT_ID} ENV VITE_APP_LOGIN_REDIRECT=${VITE_APP_LOGIN_REDIRECT} ENV VITE_APP_SUBPATH=${DJANGO_BATAI_URL_PATH} ENV DJANGO_MINIO_STORAGE_URL=${DJANGO_MINIO_STORAGE_URL} diff --git a/prod/docker-compose.prod.yml b/prod/docker-compose.prod.yml index 096a04cf..c1ffc36e 100644 --- a/prod/docker-compose.prod.yml +++ b/prod/docker-compose.prod.yml @@ -95,7 +95,6 @@ services: args: VITE_APP_API_ROOT: ${VITE_APP_API_ROOT} VITE_APP_OAUTH_API_ROOT: ${VITE_APP_OAUTH_API_ROOT} - VITE_APP_OAUTH_CLIENT_ID: ${VITE_APP_OAUTH_CLIENT_ID} VITE_APP_LOGIN_REDIRECT: ${VITE_APP_LOGIN_REDIRECT} DJANGO_BATAI_URL_PATH: ${DJANGO_BATAI_URL_PATH} DJANGO_MINIO_STORAGE_URL: ${DJANGO_MINIO_STORAGE_URL}