summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-05-29 12:34:28 +0000
committerCoprDistGit <infra@openeuler.org>2023-05-29 12:34:28 +0000
commitd015cfe5239a310db0beccc1589d0da0a72d6396 (patch)
tree9011cae13a20b822cf034705aef510c08bbfcbaf
parentf5656f5ef6a43134af880c25aea1e4c67f8f34ca (diff)
automatic import of python-django-ocs-observation-portal
-rw-r--r--.gitignore1
-rw-r--r--python-django-ocs-observation-portal.spec643
-rw-r--r--sources1
3 files changed, 645 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..015702f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/django_ocs_observation_portal-4.7.1.tar.gz
diff --git a/python-django-ocs-observation-portal.spec b/python-django-ocs-observation-portal.spec
new file mode 100644
index 0000000..b936da6
--- /dev/null
+++ b/python-django-ocs-observation-portal.spec
@@ -0,0 +1,643 @@
+%global _empty_manifest_terminate_build 0
+Name: python-django-ocs-observation-portal
+Version: 4.7.1
+Release: 1
+Summary: The Observatory Control System (OCS) Observation Portal django apps
+License: GPL-3.0-only
+URL: https://observatorycontrolsystem.github.io
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/b0/1c/360cb4fe4c088f6301d4e0acad7c110bbf21458715099c6343893aba250b/django_ocs_observation_portal-4.7.1.tar.gz
+BuildArch: noarch
+
+Requires: python3-apscheduler
+Requires: python3-boto3
+Requires: python3-cerberus
+Requires: python3-django
+Requires: python3-djangorestframework
+Requires: python3-django-bootstrap4
+Requires: python3-django-cors-headers
+Requires: python3-django-dramatiq
+Requires: python3-django-extensions
+Requires: python3-django-filter
+Requires: python3-django-oauth-toolkit
+Requires: python3-django-redis-cache
+Requires: python3-django-registration-redux
+Requires: python3-django-storages
+Requires: python3-dramatiq[redis,watch]
+Requires: python3-drf-yasg
+Requires: python3-opensearch-py
+Requires: python3-gunicorn[gevent]
+Requires: python3-lcogt-logging
+Requires: python3-numpy
+Requires: python3-ocs-rise-set
+Requires: python3-psycopg2-binary
+Requires: python3-PyPDF2
+Requires: python3-redis
+Requires: python3-requests
+Requires: python3-time_intervals
+Requires: python3-uritemplate
+Requires: python3-PyYAML
+
+%description
+# Observation Portal
+
+![Build](https://github.com/observatorycontrolsystem/observation-portal/workflows/Build/badge.svg)
+[![Coverage Status](https://coveralls.io/repos/github/observatorycontrolsystem/observation-portal/badge.svg?branch=master)](https://coveralls.io/github/observatorycontrolsystem/observation-portal?branch=master)
+[![Codacy Badge](https://api.codacy.com/project/badge/Grade/9846cee7c4904cae8864525101030169)](https://www.codacy.com/gh/observatorycontrolsystem/observation-portal?utm_source=github.com&utm_medium=referral&utm_content=observatorycontrolsystem/observation-portal&utm_campaign=Badge_Grade)
+
+## An API for Astronomical Observation Management
+
+Within an observatory control system, the observation portal provides modules for:
+
+- **Proposal management**: Calls for proposals, proposal creation, and time allocation
+- **Request management**: Observation request validation, submission, and cancellation, as well as views providing ancillary information about them
+- **Observation management**: Store and provide the telescope schedule, update observations, and update observation requests on observation update
+- **User identity management**: Oauth2 authenticated user management that can be used in other applications
+
+## Prerequisites
+
+Optional prerequisites can be skipped for reduced functionality.
+
+- Python >= 3.8
+- PostgreSQL >= 10
+- A running [Configuration Database](https://github.com/observatorycontrolsystem/configdb)
+- (Optional) A running [Downtime Database](https://github.com/observatorycontrolsystem/downtime)
+- (Optional) A running Elasticsearch
+
+
+
+## Environment Variables
+
+| | Variable | Description | Default |
+| ---------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
+| General | `DEBUG` | Whether the application should run using Django's debug mode | `False` |
+| | `SECRET_KEY` | The secret key used for sessions | _`random characters`_ |
+| | `ALLOWED_HOSTS` | Override for Django's ALLOWED_HOSTS setting | `*` |
+| | `CSRF_TRUSTED_ORIGINS` | Comma separated list of trusted origins allowed for CSRF | `None`
+| | `MAX_FAILURES_PER_REQUEST` | Maximum number of times an Observation can fail per Request before the Request is marked as FAILURE_LIMIT_REACHED. 0 means there is no max. | `0` |
+| | `MAX_IPP_VALUE` | The maximum value to be used for ipp scaling. Should be greater than 1 (1 would be no scaling) | `2.0` |
+| | `MIN_IPP_VALUE` | The minimum value to be used for ipp scaling. Should be less than 1 but greater than 0 | `0.5` |
+| | `PROPOSAL_TIME_OVERUSE_ALLOWANCE` | The amount of leeway in a proposals timeallocation before rejecting that request for scheduling. For example, a value of 1.1 results in allows over-scheduling by up to 10% of the total time_allocation. It is useful to allow some over-scheduling since it is likely some in progress observations will use less time then allocated, due to conservative overheads, failing, or cancelling. | `1.1` |
+| Database | `DB_NAME` | The name of the database | `observation_portal` |
+| | `DB_USER` | The database user | `postgres` |
+| | `DB_PASSWORD` | The database password | _`Empty string`_ |
+| | `DB_HOST` | The database host | `127.0.0.1` |
+| | `DB_PORT` | The database port | `5432` |
+| Cache | `CACHE_BACKEND` | The remote Django cache backend | `django.core.cache.backends.locmem.LocMemCache` |
+| | `CACHE_LOCATION` | The cache location or connection string | `unique-snowflake` |
+| | `LOCAL_CACHE_BACKEND` | The local Django cache backend to use | `django.core.cache.backends.locmem.LocMemCache` |
+| Static and Media Files | `AWS_BUCKET_NAME` | The name of the AWS bucket in which to store static and media files | `observation-portal-test-bucket` |
+| | `AWS_REGION` | The AWS region | `us-west-2` |
+| | `AWS_ACCESS_KEY_ID` | The AWS user access key with read/write priveleges on the s3 bucket | `None` |
+| | `AWS_SECRET_ACCESS_KEY` | The AWS user secret key to use with the access key | `None` |
+| | `MEDIA_STORAGE` | The Django media files storage backend | `django.core.files.storage.FileSystemStorage` |
+| | `MEDIAFILES_DIR` | The directory in which to store media files | `media` |
+| | `STATIC_STORAGE` | The Django static files storage backend | `django.contrib.staticfiles.storage.StaticFilesStorage` |
+| Email | `EMAIL_BACKEND` | The Django SMTP backend to use | `django.core.mail.backends.console.EmailBackend` |
+| | `EMAIL_HOST` | The SMTP host | `localhost` |
+| | `EMAIL_HOST_USER` | The SMTP user | _`Empty string`_ |
+| | `EMAIL_HOST_PASSWORD` | The SMTP password | _`Empty string`_ |
+| | `EMAIL_PORT` | The SMTP port | `587` |
+| | `ORGANIZATION_EMAIL` | The reply-to email for outgoing messages | _`Empty string`_ |
+| | `ORGANIZATION_DDT_EMAIL` | Email to receive ddt science application submission messages | _`Empty string`_ |
+| | `ORGANIZATION_ADMIN_EMAIL` | The Django Admin email to receive http 500 reports. | _`Empty string`_ |
+| | `ORGANIZATION_SUPPORT_EMAIL` | Email to receive account removal requests | _`Empty string`_ |
+| | `ORGANIZATION_NAME` | The name of your organization, used within email templates | _`Empty string`_ |
+| | `OBSERVATION_PORTAL_BASE_URL` | The base url of your deployed Observation Portal code, used within email templates to provide links to pages | `http://localhost` |
+| | `REQUESTGROUP_DATA_DOWNLOAD_URL` | The url where a user can download requestgroup data. Optionally include `{requestgroup_id}` in the string which will be filled in with the ID of the specific requestgroup. | _`Empty string`_ |
+| | `REQUEST_DETAIL_URL` | The url to frontend detail page for a Request. Optionally include `{request_id}` in the string which will be filled in with the ID of the specific request. | _`Empty string`_ |
+| | `SCIENCE_APPLICATION_DETAIL_URL` | The url to frontend science application detail page. Optionally include `{sciapp_id}` in the string which will be filled in with the ID of the specific science application. | _`Empty string`_ |
+| External Services | `CONFIGDB_URL` | The url to the configuration database | `http://localhost` |
+| | `DOWNTIMEDB_URL` | The url to the downtime database | `http://localhost` |
+| | `OPENSEARCH_URL` | The url to the OpenSearch cluster | `http://localhost` |
+| Authentication | `OAUTH_SERVER_KEY` | The secret key for client applications to verify against for authentication calls | _`Empty string`_ |
+| | `OAUTH_CLIENT_APPS_BASE_URLS` | Comma delimited set of base urls for client applications. This server will update those clients on any change in user accounts or api tokens. | _`Empty string`_ |
+| Task Scheduling | `DRAMATIQ_BROKER_URL` | The url to the dramatiq broker (if set takes precedence over `DRAMATIQ_BROKER_HOST` & `DRAMATIQ_BROKER_PORT` | `redis://redis:6379/0` |
+| | `DRAMATIQ_BROKER_HOST` | The broker host for dramatiq (deprecated) | `redis` |
+| | `DRAMATIQ_BROKER_PORT` | The broker port for dramatiq (deprecated) | `6379` |
+| Throttle Overrides | `REQUESTGROUPS_CANCEL_DEFAULT_THROTTLE` | Default django rest framework throttle rate string for the RequestGroups cancel endpoint | `2000/day` |
+| | `REQUESTGROUPS_CREATE_DEFAULT_THROTTLE` | Default django rest framework throttle rate string for the RequestGroups create endpoint | `5000/day` |
+| | `REQUESTGROUPS_VALIDATE_DEFAULT_THROTTLE` | Default django rest framework throttle rate string for the RequestGroups validate endpoint | `20000/day` |
+| Serializer Overrides | `OBSERVATIONS_SUMMARY_SERIALIZER` | Class dotpath for Observation's Summary serializer override | `observation_portal.observations.serializers.SummarySerializer` |
+| | `OBSERVATIONS_CONFIGURATIONSTATUS_SERIALIZER` | Class dotpath for Observation's ConfigurationStatus serializer override | `observation_portal.observations.serializers.ConfigurationStatusSerializer` |
+| | `OBSERVATIONS_TARGET_SERIALIZER` | Class dotpath for Observation's Target serializer override | `observation_portal.observations.serializers.ObservationTargetSerializer` |
+| | `OBSERVATIONS_CONFIGURATION_SERIALIZER` | Class dotpath for Observation's Configuration serializer override | `observation_portal.observations.serializers.ObservationConfigurationSerializer` |
+| | `OBSERVATIONS_REQUEST_SERIALIZER` | Class dotpath for Observation's Request serializer override | `observation_portal.observations.serializers.ObserveRequestSerializer` |
+| | `OBSERVATIONS_REQUESTGROUP_SERIALIZER` | Class dotpath for Observation's RequestGroup serializer override | `observation_portal.observations.serializers.ObserveRequestGroupSerializer` |
+| | `OBSERVATIONS_SCHEDULE_SERIALIZER` | Class dotpath for Observation's Schedule serializer override | `observation_portal.observations.serializers.ScheduleSerializer` |
+| | `OBSERVATIONS_OBSERVATION_SERIALIZER` | Class dotpath for Observation's Observation serializer override | `observation_portal.observations.serializers.ObservationSerializer` |
+| | `OBSERVATIONS_CANCEL_SERIALIZER` | Class dotpath for Observation's Cancel Observation serializer override | `observation_portal.observations.serializers.CancelObservationsSerializer` |
+| | `REQUESTGROUPS_CADENCE_SERIALIZER` | Class dotpath for RequestGroups's Cadence serializer override | `observation_portal.requestgroups.serializers.CadenceSerializer` |
+| | `REQUESTGROUPS_CADENCEREQUEST_SERIALIZER` | Class dotpath for RequestGroups's Cadence Request serializer override | `observation_portal.requestgroups.serializers.CadenceRequestSerializer` |
+| | `REQUESTGROUPS_CONSTRAINTS_SERIALIZER` | Class dotpath for RequestGroups's Constraints serializer override | `observation_portal.requestgroups.serializers.ConstraintsSerializer` |
+| | `REQUESTGROUPS_REGIONOFINTEREST_SERIALIZER` | Class dotpath for RequestGroups's Instrument Config ROI serializer override | `observation_portal.requestgroups.serializers.RegionOfInterestSerializer` |
+| | `REQUESTGROUPS_INSTRUMENTCONFIG_SERIALIZER` | Class dotpath for RequestGroups's Instrument Config serializer override | `observation_portal.requestgroups.serializers.InstrumentConfigSerializer` |
+| | `REQUESTGROUPS_ACQUISITIONCONFIG_SERIALIZER` | Class dotpath for RequestGroups's Acquisition Config serializer override | `observation_portal.requestgroups.serializers.AcquisitionConfigSerializer` |
+| | `REQUESTGROUPS_GUIDINGCONFIG_SERIALIZER` | Class dotpath for RequestGroups's Guiding Config serializer override | `observation_portal.requestgroups.serializers.GuidingConfigSerializer` |
+| | `REQUESTGROUPS_TARGET_SERIALIZER` | Class dotpath for RequestGroups's Target serializer override | `observation_portal.requestgroups.serializers.TargetSerializer` |
+| | `REQUESTGROUPS_CONFIGURATION_SERIALIZER` | Class dotpath for RequestGroups's Configuration serializer override | `observation_portal.requestgroups.serializers.ConfigurationSerializer` |
+| | `REQUESTGROUPS_LOCATION_SERIALIZER` | Class dotpath for RequestGroups's Location serializer override | `observation_portal.requestgroups.serializers.LocationSerializer` |
+| | `REQUESTGROUPS_WINDOW_SERIALIZER` | Class dotpath for RequestGroups's Window serializer override | `observation_portal.requestgroups.serializers.WindowSerializer` |
+| | `REQUESTGROUPS_REQUEST_SERIALIZER` | Class dotpath for RequestGroups's Request serializer override | `observation_portal.requestgroups.serializers.RequestSerializer` |
+| | `REQUESTGROUPS_REQUESTGROUP_SERIALIZER` | Class dotpath for RequestGroups's RequestGroup serializer override | `observation_portal.requestgroups.serializers.RequestGroupSerializer` |
+| | `REQUESTGROUPS_DRAFTREQUESTGROUP_SERIALIZER` | Class dotpath for RequestGroups's Draft RequestGroup serializer override | `observation_portal.requestgroups.serializers.DraftRequestGroupSerializer` |
+| | `PROPOSALS_PROPOSAL_SERIALIZER` | Class dotpath for Proposal's Proposal serializer override | `observation_portal.proposals.serializers.ProposalSerializer` |
+| | `PROPOSALS_PROPOSALINVITE_SERIALIZER` | Class dotpath for Proposal's ProposalInvite serializer override | `observation_portal.proposals.serializers.ProposalInviteSerializer` |
+| | `PROPOSALS_SEMESTER_SERIALIZER` | Class dotpath for Proposal's Semester serializer override | `observation_portal.proposals.serializers.SemesterSerialzer` |
+| | `PROPOSALS_MEMBERSHIP_SERIALIZER` | Class dotpath for Proposal's Membership serializer override | `observation_portal.proposals.serializers.MembershipSerializer` |
+| | `PROPOSALS_PROPOSALNOTIFICATION_SERIALIZER` | Class dotpath for Proposal's ProposalNotification serializer override | `observation_portal.proposals.serializers.ProposalNotificationSerializer` |
+| | `PROPOSALS_TIMELIMIT_SERIALIZER` | Class dotpath for Proposal's Proposal serializer override | `observation_portal.proposals.serializers.TimeLimitSerializer` |
+| | `ACCOUNTS_PROFILE_SERIALIZER` | Class dotpath for Accounts's Profile serializer override | `observation_portal.accounts.serializers.ProfileSerializer` |
+| | `ACCOUNTS_USER_SERIALIZER` | Class dotpath for Accounts's User serializer override | `observation_portal.accounts.serializers.UserSerializer` |
+| | `ACCOUNTS_ACCOUNTREMOVAL_SERIALIZER` | Class dotpath for Accounts's Account Removal serializer override | `observation_portal.accounts.serializers.AccountRemovalSerializer` |
+| | `SCIAPPLICATIONS_CALL_SERIALIZER` | Class dotpath for SciApplications's Call serializer override | `observation_portal.sciapplications.serializers.CallSerializer` |
+| | `SCIAPPLICATIONS_SCIENCEAPPLICATION_SERIALIZER` | Class dotpath for SciApplications's Science Application serializer override | `observation_portal.sciapplications.serializers.ScienceApplicationSerializer` |
+| as_dict Overrides | `OBSERVATIONS_SUMMARY_AS_DICT` | Class dotpath for Observation's Summary as_dict override | `observation_portal.observations.models.summary_as_dict` |
+| | `OBSERVATIONS_CONFIGURATIONSTATUS_AS_DICT` | Class dotpath for Observation's ConfigurationStatus as_dict override | `observation_portal.observations.models.configurationstatus_as_dict` |
+| | `OBSERVATIONS_OBSERVATION_AS_DICT` | Class dotpath for Observation's Observation as_dict override | `observation_portal.observations.models.observation_as_dict` |
+| | `REQUESTGROUPS_CONSTRAINTS_AS_DICT` | Class dotpath for RequestGroups's Constraints as_dict override | `observation_portal.requestgroups.models.constraints_as_dict` |
+| | `REQUESTGROUPS_REGIONOFINTEREST_AS_DICT` | Class dotpath for RequestGroups's Instrument Config ROI as_dict override | `observation_portal.requestgroups.models.regionofinterest_as_dict` |
+| | `REQUESTGROUPS_INSTRUMENTCONFIG_AS_DICT` | Class dotpath for RequestGroups's Instrument Config as_dict override | `observation_portal.requestgroups.models.instrumentconfig_as_dict` |
+| | `REQUESTGROUPS_ACQUISITIONCONFIG_AS_DICT` | Class dotpath for RequestGroups's Acquisition Config as_dict override | `observation_portal.requestgroups.models.acquisitionconfig_as_dict` |
+| | `REQUESTGROUPS_GUIDINGCONFIG_AS_DICT` | Class dotpath for RequestGroups's Guiding Config as_dict override | `observation_portal.requestgroups.models.guidingconfig_as_dict` |
+| | `REQUESTGROUPS_TARGET_AS_DICT` | Class dotpath for RequestGroups's Target as_dict override | `observation_portal.requestgroups.models.target_as_dict` |
+| | `REQUESTGROUPS_CONFIGURATION_AS_DICT` | Class dotpath for RequestGroups's Configuration as_dict override | `observation_portal.requestgroups.models.configuration_as_dict` |
+| | `REQUESTGROUPS_LOCATION_AS_DICT` | Class dotpath for RequestGroups's Location as_dict override | `observation_portal.requestgroups.models.location_as_dict` |
+| | `REQUESTGROUPS_WINDOW_AS_DICT` | Class dotpath for RequestGroups's Window as_dict override | `observation_portal.requestgroups.models.window_as_dict` |
+| | `REQUESTGROUPS_REQUEST_AS_DICT` | Class dotpath for RequestGroups's Request as_dict override | `observation_portal.requestgroups.models.request_as_dict` |
+| | `REQUESTGROUPS_REQUESTGROUP_AS_DICT` | Class dotpath for RequestGroups's RequestGroup as_dict override | `observation_portal.requestgroups.models.requestgroup_as_dict` |
+| | `PROPOSALS_PROPOSAL_AS_DICT` | Class dotpath for Proposal's Proposal as_dict override | `observation_portal.proposals.models.proposal_as_dict` |
+| | `PROPOSALS_TIMEALLOCATION_AS_DICT` | Class dotpath for Proposal's TimeAllocation as_dict override | `observation_portal.proposals.models.timeallocation_as_dict` |
+| | `PROPOSALS_MEMBERSHIP_AS_DICT` | Class dotpath for Proposal's Membership as_dict override | `observation_portal.proposals.models.membership_as_dict` |
+| duration Overrides | `INSTRUMENT_CONFIGURATION_PER_EXPOSURE_DURATION` | Class dotpath for duration_per_exposure method override | `observation_portal.requestgroups.duration_utils.get_instrument_configuration_duration_per_exposure` |
+
+
+## Local Development
+
+### **Set up external services**
+
+Please refer to the [Configuration Database](https://github.com/observatorycontrolsystem/configdb) and [Downtime Database](https://github.com/observatorycontrolsystem/downtime) projects for instructions on how to get those running, as well as the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/install-elasticsearch.html) for options on how to run Elasticsearch.
+
+
+### **Poetry**
+
+We use Poetry for package management. If you already have Poetry installed, you
+can skip this section.
+
+You can install Poetry using one of the many options listed at https://python-poetry.org/docs/#installation.
+One simple option is using Pipx:
+
+ python3 -m pip install --user pipx
+ python3 -m pipx ensurepath
+ pipx install poetry
+
+### **Install**
+
+Install the project and its Python dependencies:
+
+ poetry install
+
+This will install the project in a Poetry managed virtual environment. To run
+commands in that environment either use `poetry run ...` or start a shell in
+that environment with `poetry shell`
+
+### **Set up the database**
+
+This example uses the [PostgreSQL Docker image](https://hub.docker.com/_/postgres) to create a database. Make sure that the options that you use to set up your database correspond with your configured database settings.
+
+ docker run --name observation-portal-postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=observation_portal -v/var/lib/postgresql/data -p5432:5432 -d postgres:11.1
+
+After creating the database, migrations must be applied to set up the tables in the database.
+
+ poetry run python manage.py migrate
+
+### **Run the tests**
+
+ poetry run python manage.py test --settings=observation_portal.test_settings
+
+### **Run the portal**
+
+ poetry run python manage.py runserver
+
+The observation portal should now be accessible from <http://127.0.0.1:8000>!
+
+
+%package -n python3-django-ocs-observation-portal
+Summary: The Observatory Control System (OCS) Observation Portal django apps
+Provides: python-django-ocs-observation-portal
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-django-ocs-observation-portal
+# Observation Portal
+
+![Build](https://github.com/observatorycontrolsystem/observation-portal/workflows/Build/badge.svg)
+[![Coverage Status](https://coveralls.io/repos/github/observatorycontrolsystem/observation-portal/badge.svg?branch=master)](https://coveralls.io/github/observatorycontrolsystem/observation-portal?branch=master)
+[![Codacy Badge](https://api.codacy.com/project/badge/Grade/9846cee7c4904cae8864525101030169)](https://www.codacy.com/gh/observatorycontrolsystem/observation-portal?utm_source=github.com&utm_medium=referral&utm_content=observatorycontrolsystem/observation-portal&utm_campaign=Badge_Grade)
+
+## An API for Astronomical Observation Management
+
+Within an observatory control system, the observation portal provides modules for:
+
+- **Proposal management**: Calls for proposals, proposal creation, and time allocation
+- **Request management**: Observation request validation, submission, and cancellation, as well as views providing ancillary information about them
+- **Observation management**: Store and provide the telescope schedule, update observations, and update observation requests on observation update
+- **User identity management**: Oauth2 authenticated user management that can be used in other applications
+
+## Prerequisites
+
+Optional prerequisites can be skipped for reduced functionality.
+
+- Python >= 3.8
+- PostgreSQL >= 10
+- A running [Configuration Database](https://github.com/observatorycontrolsystem/configdb)
+- (Optional) A running [Downtime Database](https://github.com/observatorycontrolsystem/downtime)
+- (Optional) A running Elasticsearch
+
+
+
+## Environment Variables
+
+| | Variable | Description | Default |
+| ---------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
+| General | `DEBUG` | Whether the application should run using Django's debug mode | `False` |
+| | `SECRET_KEY` | The secret key used for sessions | _`random characters`_ |
+| | `ALLOWED_HOSTS` | Override for Django's ALLOWED_HOSTS setting | `*` |
+| | `CSRF_TRUSTED_ORIGINS` | Comma separated list of trusted origins allowed for CSRF | `None`
+| | `MAX_FAILURES_PER_REQUEST` | Maximum number of times an Observation can fail per Request before the Request is marked as FAILURE_LIMIT_REACHED. 0 means there is no max. | `0` |
+| | `MAX_IPP_VALUE` | The maximum value to be used for ipp scaling. Should be greater than 1 (1 would be no scaling) | `2.0` |
+| | `MIN_IPP_VALUE` | The minimum value to be used for ipp scaling. Should be less than 1 but greater than 0 | `0.5` |
+| | `PROPOSAL_TIME_OVERUSE_ALLOWANCE` | The amount of leeway in a proposals timeallocation before rejecting that request for scheduling. For example, a value of 1.1 results in allows over-scheduling by up to 10% of the total time_allocation. It is useful to allow some over-scheduling since it is likely some in progress observations will use less time then allocated, due to conservative overheads, failing, or cancelling. | `1.1` |
+| Database | `DB_NAME` | The name of the database | `observation_portal` |
+| | `DB_USER` | The database user | `postgres` |
+| | `DB_PASSWORD` | The database password | _`Empty string`_ |
+| | `DB_HOST` | The database host | `127.0.0.1` |
+| | `DB_PORT` | The database port | `5432` |
+| Cache | `CACHE_BACKEND` | The remote Django cache backend | `django.core.cache.backends.locmem.LocMemCache` |
+| | `CACHE_LOCATION` | The cache location or connection string | `unique-snowflake` |
+| | `LOCAL_CACHE_BACKEND` | The local Django cache backend to use | `django.core.cache.backends.locmem.LocMemCache` |
+| Static and Media Files | `AWS_BUCKET_NAME` | The name of the AWS bucket in which to store static and media files | `observation-portal-test-bucket` |
+| | `AWS_REGION` | The AWS region | `us-west-2` |
+| | `AWS_ACCESS_KEY_ID` | The AWS user access key with read/write priveleges on the s3 bucket | `None` |
+| | `AWS_SECRET_ACCESS_KEY` | The AWS user secret key to use with the access key | `None` |
+| | `MEDIA_STORAGE` | The Django media files storage backend | `django.core.files.storage.FileSystemStorage` |
+| | `MEDIAFILES_DIR` | The directory in which to store media files | `media` |
+| | `STATIC_STORAGE` | The Django static files storage backend | `django.contrib.staticfiles.storage.StaticFilesStorage` |
+| Email | `EMAIL_BACKEND` | The Django SMTP backend to use | `django.core.mail.backends.console.EmailBackend` |
+| | `EMAIL_HOST` | The SMTP host | `localhost` |
+| | `EMAIL_HOST_USER` | The SMTP user | _`Empty string`_ |
+| | `EMAIL_HOST_PASSWORD` | The SMTP password | _`Empty string`_ |
+| | `EMAIL_PORT` | The SMTP port | `587` |
+| | `ORGANIZATION_EMAIL` | The reply-to email for outgoing messages | _`Empty string`_ |
+| | `ORGANIZATION_DDT_EMAIL` | Email to receive ddt science application submission messages | _`Empty string`_ |
+| | `ORGANIZATION_ADMIN_EMAIL` | The Django Admin email to receive http 500 reports. | _`Empty string`_ |
+| | `ORGANIZATION_SUPPORT_EMAIL` | Email to receive account removal requests | _`Empty string`_ |
+| | `ORGANIZATION_NAME` | The name of your organization, used within email templates | _`Empty string`_ |
+| | `OBSERVATION_PORTAL_BASE_URL` | The base url of your deployed Observation Portal code, used within email templates to provide links to pages | `http://localhost` |
+| | `REQUESTGROUP_DATA_DOWNLOAD_URL` | The url where a user can download requestgroup data. Optionally include `{requestgroup_id}` in the string which will be filled in with the ID of the specific requestgroup. | _`Empty string`_ |
+| | `REQUEST_DETAIL_URL` | The url to frontend detail page for a Request. Optionally include `{request_id}` in the string which will be filled in with the ID of the specific request. | _`Empty string`_ |
+| | `SCIENCE_APPLICATION_DETAIL_URL` | The url to frontend science application detail page. Optionally include `{sciapp_id}` in the string which will be filled in with the ID of the specific science application. | _`Empty string`_ |
+| External Services | `CONFIGDB_URL` | The url to the configuration database | `http://localhost` |
+| | `DOWNTIMEDB_URL` | The url to the downtime database | `http://localhost` |
+| | `OPENSEARCH_URL` | The url to the OpenSearch cluster | `http://localhost` |
+| Authentication | `OAUTH_SERVER_KEY` | The secret key for client applications to verify against for authentication calls | _`Empty string`_ |
+| | `OAUTH_CLIENT_APPS_BASE_URLS` | Comma delimited set of base urls for client applications. This server will update those clients on any change in user accounts or api tokens. | _`Empty string`_ |
+| Task Scheduling | `DRAMATIQ_BROKER_URL` | The url to the dramatiq broker (if set takes precedence over `DRAMATIQ_BROKER_HOST` & `DRAMATIQ_BROKER_PORT` | `redis://redis:6379/0` |
+| | `DRAMATIQ_BROKER_HOST` | The broker host for dramatiq (deprecated) | `redis` |
+| | `DRAMATIQ_BROKER_PORT` | The broker port for dramatiq (deprecated) | `6379` |
+| Throttle Overrides | `REQUESTGROUPS_CANCEL_DEFAULT_THROTTLE` | Default django rest framework throttle rate string for the RequestGroups cancel endpoint | `2000/day` |
+| | `REQUESTGROUPS_CREATE_DEFAULT_THROTTLE` | Default django rest framework throttle rate string for the RequestGroups create endpoint | `5000/day` |
+| | `REQUESTGROUPS_VALIDATE_DEFAULT_THROTTLE` | Default django rest framework throttle rate string for the RequestGroups validate endpoint | `20000/day` |
+| Serializer Overrides | `OBSERVATIONS_SUMMARY_SERIALIZER` | Class dotpath for Observation's Summary serializer override | `observation_portal.observations.serializers.SummarySerializer` |
+| | `OBSERVATIONS_CONFIGURATIONSTATUS_SERIALIZER` | Class dotpath for Observation's ConfigurationStatus serializer override | `observation_portal.observations.serializers.ConfigurationStatusSerializer` |
+| | `OBSERVATIONS_TARGET_SERIALIZER` | Class dotpath for Observation's Target serializer override | `observation_portal.observations.serializers.ObservationTargetSerializer` |
+| | `OBSERVATIONS_CONFIGURATION_SERIALIZER` | Class dotpath for Observation's Configuration serializer override | `observation_portal.observations.serializers.ObservationConfigurationSerializer` |
+| | `OBSERVATIONS_REQUEST_SERIALIZER` | Class dotpath for Observation's Request serializer override | `observation_portal.observations.serializers.ObserveRequestSerializer` |
+| | `OBSERVATIONS_REQUESTGROUP_SERIALIZER` | Class dotpath for Observation's RequestGroup serializer override | `observation_portal.observations.serializers.ObserveRequestGroupSerializer` |
+| | `OBSERVATIONS_SCHEDULE_SERIALIZER` | Class dotpath for Observation's Schedule serializer override | `observation_portal.observations.serializers.ScheduleSerializer` |
+| | `OBSERVATIONS_OBSERVATION_SERIALIZER` | Class dotpath for Observation's Observation serializer override | `observation_portal.observations.serializers.ObservationSerializer` |
+| | `OBSERVATIONS_CANCEL_SERIALIZER` | Class dotpath for Observation's Cancel Observation serializer override | `observation_portal.observations.serializers.CancelObservationsSerializer` |
+| | `REQUESTGROUPS_CADENCE_SERIALIZER` | Class dotpath for RequestGroups's Cadence serializer override | `observation_portal.requestgroups.serializers.CadenceSerializer` |
+| | `REQUESTGROUPS_CADENCEREQUEST_SERIALIZER` | Class dotpath for RequestGroups's Cadence Request serializer override | `observation_portal.requestgroups.serializers.CadenceRequestSerializer` |
+| | `REQUESTGROUPS_CONSTRAINTS_SERIALIZER` | Class dotpath for RequestGroups's Constraints serializer override | `observation_portal.requestgroups.serializers.ConstraintsSerializer` |
+| | `REQUESTGROUPS_REGIONOFINTEREST_SERIALIZER` | Class dotpath for RequestGroups's Instrument Config ROI serializer override | `observation_portal.requestgroups.serializers.RegionOfInterestSerializer` |
+| | `REQUESTGROUPS_INSTRUMENTCONFIG_SERIALIZER` | Class dotpath for RequestGroups's Instrument Config serializer override | `observation_portal.requestgroups.serializers.InstrumentConfigSerializer` |
+| | `REQUESTGROUPS_ACQUISITIONCONFIG_SERIALIZER` | Class dotpath for RequestGroups's Acquisition Config serializer override | `observation_portal.requestgroups.serializers.AcquisitionConfigSerializer` |
+| | `REQUESTGROUPS_GUIDINGCONFIG_SERIALIZER` | Class dotpath for RequestGroups's Guiding Config serializer override | `observation_portal.requestgroups.serializers.GuidingConfigSerializer` |
+| | `REQUESTGROUPS_TARGET_SERIALIZER` | Class dotpath for RequestGroups's Target serializer override | `observation_portal.requestgroups.serializers.TargetSerializer` |
+| | `REQUESTGROUPS_CONFIGURATION_SERIALIZER` | Class dotpath for RequestGroups's Configuration serializer override | `observation_portal.requestgroups.serializers.ConfigurationSerializer` |
+| | `REQUESTGROUPS_LOCATION_SERIALIZER` | Class dotpath for RequestGroups's Location serializer override | `observation_portal.requestgroups.serializers.LocationSerializer` |
+| | `REQUESTGROUPS_WINDOW_SERIALIZER` | Class dotpath for RequestGroups's Window serializer override | `observation_portal.requestgroups.serializers.WindowSerializer` |
+| | `REQUESTGROUPS_REQUEST_SERIALIZER` | Class dotpath for RequestGroups's Request serializer override | `observation_portal.requestgroups.serializers.RequestSerializer` |
+| | `REQUESTGROUPS_REQUESTGROUP_SERIALIZER` | Class dotpath for RequestGroups's RequestGroup serializer override | `observation_portal.requestgroups.serializers.RequestGroupSerializer` |
+| | `REQUESTGROUPS_DRAFTREQUESTGROUP_SERIALIZER` | Class dotpath for RequestGroups's Draft RequestGroup serializer override | `observation_portal.requestgroups.serializers.DraftRequestGroupSerializer` |
+| | `PROPOSALS_PROPOSAL_SERIALIZER` | Class dotpath for Proposal's Proposal serializer override | `observation_portal.proposals.serializers.ProposalSerializer` |
+| | `PROPOSALS_PROPOSALINVITE_SERIALIZER` | Class dotpath for Proposal's ProposalInvite serializer override | `observation_portal.proposals.serializers.ProposalInviteSerializer` |
+| | `PROPOSALS_SEMESTER_SERIALIZER` | Class dotpath for Proposal's Semester serializer override | `observation_portal.proposals.serializers.SemesterSerialzer` |
+| | `PROPOSALS_MEMBERSHIP_SERIALIZER` | Class dotpath for Proposal's Membership serializer override | `observation_portal.proposals.serializers.MembershipSerializer` |
+| | `PROPOSALS_PROPOSALNOTIFICATION_SERIALIZER` | Class dotpath for Proposal's ProposalNotification serializer override | `observation_portal.proposals.serializers.ProposalNotificationSerializer` |
+| | `PROPOSALS_TIMELIMIT_SERIALIZER` | Class dotpath for Proposal's Proposal serializer override | `observation_portal.proposals.serializers.TimeLimitSerializer` |
+| | `ACCOUNTS_PROFILE_SERIALIZER` | Class dotpath for Accounts's Profile serializer override | `observation_portal.accounts.serializers.ProfileSerializer` |
+| | `ACCOUNTS_USER_SERIALIZER` | Class dotpath for Accounts's User serializer override | `observation_portal.accounts.serializers.UserSerializer` |
+| | `ACCOUNTS_ACCOUNTREMOVAL_SERIALIZER` | Class dotpath for Accounts's Account Removal serializer override | `observation_portal.accounts.serializers.AccountRemovalSerializer` |
+| | `SCIAPPLICATIONS_CALL_SERIALIZER` | Class dotpath for SciApplications's Call serializer override | `observation_portal.sciapplications.serializers.CallSerializer` |
+| | `SCIAPPLICATIONS_SCIENCEAPPLICATION_SERIALIZER` | Class dotpath for SciApplications's Science Application serializer override | `observation_portal.sciapplications.serializers.ScienceApplicationSerializer` |
+| as_dict Overrides | `OBSERVATIONS_SUMMARY_AS_DICT` | Class dotpath for Observation's Summary as_dict override | `observation_portal.observations.models.summary_as_dict` |
+| | `OBSERVATIONS_CONFIGURATIONSTATUS_AS_DICT` | Class dotpath for Observation's ConfigurationStatus as_dict override | `observation_portal.observations.models.configurationstatus_as_dict` |
+| | `OBSERVATIONS_OBSERVATION_AS_DICT` | Class dotpath for Observation's Observation as_dict override | `observation_portal.observations.models.observation_as_dict` |
+| | `REQUESTGROUPS_CONSTRAINTS_AS_DICT` | Class dotpath for RequestGroups's Constraints as_dict override | `observation_portal.requestgroups.models.constraints_as_dict` |
+| | `REQUESTGROUPS_REGIONOFINTEREST_AS_DICT` | Class dotpath for RequestGroups's Instrument Config ROI as_dict override | `observation_portal.requestgroups.models.regionofinterest_as_dict` |
+| | `REQUESTGROUPS_INSTRUMENTCONFIG_AS_DICT` | Class dotpath for RequestGroups's Instrument Config as_dict override | `observation_portal.requestgroups.models.instrumentconfig_as_dict` |
+| | `REQUESTGROUPS_ACQUISITIONCONFIG_AS_DICT` | Class dotpath for RequestGroups's Acquisition Config as_dict override | `observation_portal.requestgroups.models.acquisitionconfig_as_dict` |
+| | `REQUESTGROUPS_GUIDINGCONFIG_AS_DICT` | Class dotpath for RequestGroups's Guiding Config as_dict override | `observation_portal.requestgroups.models.guidingconfig_as_dict` |
+| | `REQUESTGROUPS_TARGET_AS_DICT` | Class dotpath for RequestGroups's Target as_dict override | `observation_portal.requestgroups.models.target_as_dict` |
+| | `REQUESTGROUPS_CONFIGURATION_AS_DICT` | Class dotpath for RequestGroups's Configuration as_dict override | `observation_portal.requestgroups.models.configuration_as_dict` |
+| | `REQUESTGROUPS_LOCATION_AS_DICT` | Class dotpath for RequestGroups's Location as_dict override | `observation_portal.requestgroups.models.location_as_dict` |
+| | `REQUESTGROUPS_WINDOW_AS_DICT` | Class dotpath for RequestGroups's Window as_dict override | `observation_portal.requestgroups.models.window_as_dict` |
+| | `REQUESTGROUPS_REQUEST_AS_DICT` | Class dotpath for RequestGroups's Request as_dict override | `observation_portal.requestgroups.models.request_as_dict` |
+| | `REQUESTGROUPS_REQUESTGROUP_AS_DICT` | Class dotpath for RequestGroups's RequestGroup as_dict override | `observation_portal.requestgroups.models.requestgroup_as_dict` |
+| | `PROPOSALS_PROPOSAL_AS_DICT` | Class dotpath for Proposal's Proposal as_dict override | `observation_portal.proposals.models.proposal_as_dict` |
+| | `PROPOSALS_TIMEALLOCATION_AS_DICT` | Class dotpath for Proposal's TimeAllocation as_dict override | `observation_portal.proposals.models.timeallocation_as_dict` |
+| | `PROPOSALS_MEMBERSHIP_AS_DICT` | Class dotpath for Proposal's Membership as_dict override | `observation_portal.proposals.models.membership_as_dict` |
+| duration Overrides | `INSTRUMENT_CONFIGURATION_PER_EXPOSURE_DURATION` | Class dotpath for duration_per_exposure method override | `observation_portal.requestgroups.duration_utils.get_instrument_configuration_duration_per_exposure` |
+
+
+## Local Development
+
+### **Set up external services**
+
+Please refer to the [Configuration Database](https://github.com/observatorycontrolsystem/configdb) and [Downtime Database](https://github.com/observatorycontrolsystem/downtime) projects for instructions on how to get those running, as well as the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/install-elasticsearch.html) for options on how to run Elasticsearch.
+
+
+### **Poetry**
+
+We use Poetry for package management. If you already have Poetry installed, you
+can skip this section.
+
+You can install Poetry using one of the many options listed at https://python-poetry.org/docs/#installation.
+One simple option is using Pipx:
+
+ python3 -m pip install --user pipx
+ python3 -m pipx ensurepath
+ pipx install poetry
+
+### **Install**
+
+Install the project and its Python dependencies:
+
+ poetry install
+
+This will install the project in a Poetry managed virtual environment. To run
+commands in that environment either use `poetry run ...` or start a shell in
+that environment with `poetry shell`
+
+### **Set up the database**
+
+This example uses the [PostgreSQL Docker image](https://hub.docker.com/_/postgres) to create a database. Make sure that the options that you use to set up your database correspond with your configured database settings.
+
+ docker run --name observation-portal-postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=observation_portal -v/var/lib/postgresql/data -p5432:5432 -d postgres:11.1
+
+After creating the database, migrations must be applied to set up the tables in the database.
+
+ poetry run python manage.py migrate
+
+### **Run the tests**
+
+ poetry run python manage.py test --settings=observation_portal.test_settings
+
+### **Run the portal**
+
+ poetry run python manage.py runserver
+
+The observation portal should now be accessible from <http://127.0.0.1:8000>!
+
+
+%package help
+Summary: Development documents and examples for django-ocs-observation-portal
+Provides: python3-django-ocs-observation-portal-doc
+%description help
+# Observation Portal
+
+![Build](https://github.com/observatorycontrolsystem/observation-portal/workflows/Build/badge.svg)
+[![Coverage Status](https://coveralls.io/repos/github/observatorycontrolsystem/observation-portal/badge.svg?branch=master)](https://coveralls.io/github/observatorycontrolsystem/observation-portal?branch=master)
+[![Codacy Badge](https://api.codacy.com/project/badge/Grade/9846cee7c4904cae8864525101030169)](https://www.codacy.com/gh/observatorycontrolsystem/observation-portal?utm_source=github.com&utm_medium=referral&utm_content=observatorycontrolsystem/observation-portal&utm_campaign=Badge_Grade)
+
+## An API for Astronomical Observation Management
+
+Within an observatory control system, the observation portal provides modules for:
+
+- **Proposal management**: Calls for proposals, proposal creation, and time allocation
+- **Request management**: Observation request validation, submission, and cancellation, as well as views providing ancillary information about them
+- **Observation management**: Store and provide the telescope schedule, update observations, and update observation requests on observation update
+- **User identity management**: Oauth2 authenticated user management that can be used in other applications
+
+## Prerequisites
+
+Optional prerequisites can be skipped for reduced functionality.
+
+- Python >= 3.8
+- PostgreSQL >= 10
+- A running [Configuration Database](https://github.com/observatorycontrolsystem/configdb)
+- (Optional) A running [Downtime Database](https://github.com/observatorycontrolsystem/downtime)
+- (Optional) A running Elasticsearch
+
+
+
+## Environment Variables
+
+| | Variable | Description | Default |
+| ---------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
+| General | `DEBUG` | Whether the application should run using Django's debug mode | `False` |
+| | `SECRET_KEY` | The secret key used for sessions | _`random characters`_ |
+| | `ALLOWED_HOSTS` | Override for Django's ALLOWED_HOSTS setting | `*` |
+| | `CSRF_TRUSTED_ORIGINS` | Comma separated list of trusted origins allowed for CSRF | `None`
+| | `MAX_FAILURES_PER_REQUEST` | Maximum number of times an Observation can fail per Request before the Request is marked as FAILURE_LIMIT_REACHED. 0 means there is no max. | `0` |
+| | `MAX_IPP_VALUE` | The maximum value to be used for ipp scaling. Should be greater than 1 (1 would be no scaling) | `2.0` |
+| | `MIN_IPP_VALUE` | The minimum value to be used for ipp scaling. Should be less than 1 but greater than 0 | `0.5` |
+| | `PROPOSAL_TIME_OVERUSE_ALLOWANCE` | The amount of leeway in a proposals timeallocation before rejecting that request for scheduling. For example, a value of 1.1 results in allows over-scheduling by up to 10% of the total time_allocation. It is useful to allow some over-scheduling since it is likely some in progress observations will use less time then allocated, due to conservative overheads, failing, or cancelling. | `1.1` |
+| Database | `DB_NAME` | The name of the database | `observation_portal` |
+| | `DB_USER` | The database user | `postgres` |
+| | `DB_PASSWORD` | The database password | _`Empty string`_ |
+| | `DB_HOST` | The database host | `127.0.0.1` |
+| | `DB_PORT` | The database port | `5432` |
+| Cache | `CACHE_BACKEND` | The remote Django cache backend | `django.core.cache.backends.locmem.LocMemCache` |
+| | `CACHE_LOCATION` | The cache location or connection string | `unique-snowflake` |
+| | `LOCAL_CACHE_BACKEND` | The local Django cache backend to use | `django.core.cache.backends.locmem.LocMemCache` |
+| Static and Media Files | `AWS_BUCKET_NAME` | The name of the AWS bucket in which to store static and media files | `observation-portal-test-bucket` |
+| | `AWS_REGION` | The AWS region | `us-west-2` |
+| | `AWS_ACCESS_KEY_ID` | The AWS user access key with read/write priveleges on the s3 bucket | `None` |
+| | `AWS_SECRET_ACCESS_KEY` | The AWS user secret key to use with the access key | `None` |
+| | `MEDIA_STORAGE` | The Django media files storage backend | `django.core.files.storage.FileSystemStorage` |
+| | `MEDIAFILES_DIR` | The directory in which to store media files | `media` |
+| | `STATIC_STORAGE` | The Django static files storage backend | `django.contrib.staticfiles.storage.StaticFilesStorage` |
+| Email | `EMAIL_BACKEND` | The Django SMTP backend to use | `django.core.mail.backends.console.EmailBackend` |
+| | `EMAIL_HOST` | The SMTP host | `localhost` |
+| | `EMAIL_HOST_USER` | The SMTP user | _`Empty string`_ |
+| | `EMAIL_HOST_PASSWORD` | The SMTP password | _`Empty string`_ |
+| | `EMAIL_PORT` | The SMTP port | `587` |
+| | `ORGANIZATION_EMAIL` | The reply-to email for outgoing messages | _`Empty string`_ |
+| | `ORGANIZATION_DDT_EMAIL` | Email to receive ddt science application submission messages | _`Empty string`_ |
+| | `ORGANIZATION_ADMIN_EMAIL` | The Django Admin email to receive http 500 reports. | _`Empty string`_ |
+| | `ORGANIZATION_SUPPORT_EMAIL` | Email to receive account removal requests | _`Empty string`_ |
+| | `ORGANIZATION_NAME` | The name of your organization, used within email templates | _`Empty string`_ |
+| | `OBSERVATION_PORTAL_BASE_URL` | The base url of your deployed Observation Portal code, used within email templates to provide links to pages | `http://localhost` |
+| | `REQUESTGROUP_DATA_DOWNLOAD_URL` | The url where a user can download requestgroup data. Optionally include `{requestgroup_id}` in the string which will be filled in with the ID of the specific requestgroup. | _`Empty string`_ |
+| | `REQUEST_DETAIL_URL` | The url to frontend detail page for a Request. Optionally include `{request_id}` in the string which will be filled in with the ID of the specific request. | _`Empty string`_ |
+| | `SCIENCE_APPLICATION_DETAIL_URL` | The url to frontend science application detail page. Optionally include `{sciapp_id}` in the string which will be filled in with the ID of the specific science application. | _`Empty string`_ |
+| External Services | `CONFIGDB_URL` | The url to the configuration database | `http://localhost` |
+| | `DOWNTIMEDB_URL` | The url to the downtime database | `http://localhost` |
+| | `OPENSEARCH_URL` | The url to the OpenSearch cluster | `http://localhost` |
+| Authentication | `OAUTH_SERVER_KEY` | The secret key for client applications to verify against for authentication calls | _`Empty string`_ |
+| | `OAUTH_CLIENT_APPS_BASE_URLS` | Comma delimited set of base urls for client applications. This server will update those clients on any change in user accounts or api tokens. | _`Empty string`_ |
+| Task Scheduling | `DRAMATIQ_BROKER_URL` | The url to the dramatiq broker (if set takes precedence over `DRAMATIQ_BROKER_HOST` & `DRAMATIQ_BROKER_PORT` | `redis://redis:6379/0` |
+| | `DRAMATIQ_BROKER_HOST` | The broker host for dramatiq (deprecated) | `redis` |
+| | `DRAMATIQ_BROKER_PORT` | The broker port for dramatiq (deprecated) | `6379` |
+| Throttle Overrides | `REQUESTGROUPS_CANCEL_DEFAULT_THROTTLE` | Default django rest framework throttle rate string for the RequestGroups cancel endpoint | `2000/day` |
+| | `REQUESTGROUPS_CREATE_DEFAULT_THROTTLE` | Default django rest framework throttle rate string for the RequestGroups create endpoint | `5000/day` |
+| | `REQUESTGROUPS_VALIDATE_DEFAULT_THROTTLE` | Default django rest framework throttle rate string for the RequestGroups validate endpoint | `20000/day` |
+| Serializer Overrides | `OBSERVATIONS_SUMMARY_SERIALIZER` | Class dotpath for Observation's Summary serializer override | `observation_portal.observations.serializers.SummarySerializer` |
+| | `OBSERVATIONS_CONFIGURATIONSTATUS_SERIALIZER` | Class dotpath for Observation's ConfigurationStatus serializer override | `observation_portal.observations.serializers.ConfigurationStatusSerializer` |
+| | `OBSERVATIONS_TARGET_SERIALIZER` | Class dotpath for Observation's Target serializer override | `observation_portal.observations.serializers.ObservationTargetSerializer` |
+| | `OBSERVATIONS_CONFIGURATION_SERIALIZER` | Class dotpath for Observation's Configuration serializer override | `observation_portal.observations.serializers.ObservationConfigurationSerializer` |
+| | `OBSERVATIONS_REQUEST_SERIALIZER` | Class dotpath for Observation's Request serializer override | `observation_portal.observations.serializers.ObserveRequestSerializer` |
+| | `OBSERVATIONS_REQUESTGROUP_SERIALIZER` | Class dotpath for Observation's RequestGroup serializer override | `observation_portal.observations.serializers.ObserveRequestGroupSerializer` |
+| | `OBSERVATIONS_SCHEDULE_SERIALIZER` | Class dotpath for Observation's Schedule serializer override | `observation_portal.observations.serializers.ScheduleSerializer` |
+| | `OBSERVATIONS_OBSERVATION_SERIALIZER` | Class dotpath for Observation's Observation serializer override | `observation_portal.observations.serializers.ObservationSerializer` |
+| | `OBSERVATIONS_CANCEL_SERIALIZER` | Class dotpath for Observation's Cancel Observation serializer override | `observation_portal.observations.serializers.CancelObservationsSerializer` |
+| | `REQUESTGROUPS_CADENCE_SERIALIZER` | Class dotpath for RequestGroups's Cadence serializer override | `observation_portal.requestgroups.serializers.CadenceSerializer` |
+| | `REQUESTGROUPS_CADENCEREQUEST_SERIALIZER` | Class dotpath for RequestGroups's Cadence Request serializer override | `observation_portal.requestgroups.serializers.CadenceRequestSerializer` |
+| | `REQUESTGROUPS_CONSTRAINTS_SERIALIZER` | Class dotpath for RequestGroups's Constraints serializer override | `observation_portal.requestgroups.serializers.ConstraintsSerializer` |
+| | `REQUESTGROUPS_REGIONOFINTEREST_SERIALIZER` | Class dotpath for RequestGroups's Instrument Config ROI serializer override | `observation_portal.requestgroups.serializers.RegionOfInterestSerializer` |
+| | `REQUESTGROUPS_INSTRUMENTCONFIG_SERIALIZER` | Class dotpath for RequestGroups's Instrument Config serializer override | `observation_portal.requestgroups.serializers.InstrumentConfigSerializer` |
+| | `REQUESTGROUPS_ACQUISITIONCONFIG_SERIALIZER` | Class dotpath for RequestGroups's Acquisition Config serializer override | `observation_portal.requestgroups.serializers.AcquisitionConfigSerializer` |
+| | `REQUESTGROUPS_GUIDINGCONFIG_SERIALIZER` | Class dotpath for RequestGroups's Guiding Config serializer override | `observation_portal.requestgroups.serializers.GuidingConfigSerializer` |
+| | `REQUESTGROUPS_TARGET_SERIALIZER` | Class dotpath for RequestGroups's Target serializer override | `observation_portal.requestgroups.serializers.TargetSerializer` |
+| | `REQUESTGROUPS_CONFIGURATION_SERIALIZER` | Class dotpath for RequestGroups's Configuration serializer override | `observation_portal.requestgroups.serializers.ConfigurationSerializer` |
+| | `REQUESTGROUPS_LOCATION_SERIALIZER` | Class dotpath for RequestGroups's Location serializer override | `observation_portal.requestgroups.serializers.LocationSerializer` |
+| | `REQUESTGROUPS_WINDOW_SERIALIZER` | Class dotpath for RequestGroups's Window serializer override | `observation_portal.requestgroups.serializers.WindowSerializer` |
+| | `REQUESTGROUPS_REQUEST_SERIALIZER` | Class dotpath for RequestGroups's Request serializer override | `observation_portal.requestgroups.serializers.RequestSerializer` |
+| | `REQUESTGROUPS_REQUESTGROUP_SERIALIZER` | Class dotpath for RequestGroups's RequestGroup serializer override | `observation_portal.requestgroups.serializers.RequestGroupSerializer` |
+| | `REQUESTGROUPS_DRAFTREQUESTGROUP_SERIALIZER` | Class dotpath for RequestGroups's Draft RequestGroup serializer override | `observation_portal.requestgroups.serializers.DraftRequestGroupSerializer` |
+| | `PROPOSALS_PROPOSAL_SERIALIZER` | Class dotpath for Proposal's Proposal serializer override | `observation_portal.proposals.serializers.ProposalSerializer` |
+| | `PROPOSALS_PROPOSALINVITE_SERIALIZER` | Class dotpath for Proposal's ProposalInvite serializer override | `observation_portal.proposals.serializers.ProposalInviteSerializer` |
+| | `PROPOSALS_SEMESTER_SERIALIZER` | Class dotpath for Proposal's Semester serializer override | `observation_portal.proposals.serializers.SemesterSerialzer` |
+| | `PROPOSALS_MEMBERSHIP_SERIALIZER` | Class dotpath for Proposal's Membership serializer override | `observation_portal.proposals.serializers.MembershipSerializer` |
+| | `PROPOSALS_PROPOSALNOTIFICATION_SERIALIZER` | Class dotpath for Proposal's ProposalNotification serializer override | `observation_portal.proposals.serializers.ProposalNotificationSerializer` |
+| | `PROPOSALS_TIMELIMIT_SERIALIZER` | Class dotpath for Proposal's Proposal serializer override | `observation_portal.proposals.serializers.TimeLimitSerializer` |
+| | `ACCOUNTS_PROFILE_SERIALIZER` | Class dotpath for Accounts's Profile serializer override | `observation_portal.accounts.serializers.ProfileSerializer` |
+| | `ACCOUNTS_USER_SERIALIZER` | Class dotpath for Accounts's User serializer override | `observation_portal.accounts.serializers.UserSerializer` |
+| | `ACCOUNTS_ACCOUNTREMOVAL_SERIALIZER` | Class dotpath for Accounts's Account Removal serializer override | `observation_portal.accounts.serializers.AccountRemovalSerializer` |
+| | `SCIAPPLICATIONS_CALL_SERIALIZER` | Class dotpath for SciApplications's Call serializer override | `observation_portal.sciapplications.serializers.CallSerializer` |
+| | `SCIAPPLICATIONS_SCIENCEAPPLICATION_SERIALIZER` | Class dotpath for SciApplications's Science Application serializer override | `observation_portal.sciapplications.serializers.ScienceApplicationSerializer` |
+| as_dict Overrides | `OBSERVATIONS_SUMMARY_AS_DICT` | Class dotpath for Observation's Summary as_dict override | `observation_portal.observations.models.summary_as_dict` |
+| | `OBSERVATIONS_CONFIGURATIONSTATUS_AS_DICT` | Class dotpath for Observation's ConfigurationStatus as_dict override | `observation_portal.observations.models.configurationstatus_as_dict` |
+| | `OBSERVATIONS_OBSERVATION_AS_DICT` | Class dotpath for Observation's Observation as_dict override | `observation_portal.observations.models.observation_as_dict` |
+| | `REQUESTGROUPS_CONSTRAINTS_AS_DICT` | Class dotpath for RequestGroups's Constraints as_dict override | `observation_portal.requestgroups.models.constraints_as_dict` |
+| | `REQUESTGROUPS_REGIONOFINTEREST_AS_DICT` | Class dotpath for RequestGroups's Instrument Config ROI as_dict override | `observation_portal.requestgroups.models.regionofinterest_as_dict` |
+| | `REQUESTGROUPS_INSTRUMENTCONFIG_AS_DICT` | Class dotpath for RequestGroups's Instrument Config as_dict override | `observation_portal.requestgroups.models.instrumentconfig_as_dict` |
+| | `REQUESTGROUPS_ACQUISITIONCONFIG_AS_DICT` | Class dotpath for RequestGroups's Acquisition Config as_dict override | `observation_portal.requestgroups.models.acquisitionconfig_as_dict` |
+| | `REQUESTGROUPS_GUIDINGCONFIG_AS_DICT` | Class dotpath for RequestGroups's Guiding Config as_dict override | `observation_portal.requestgroups.models.guidingconfig_as_dict` |
+| | `REQUESTGROUPS_TARGET_AS_DICT` | Class dotpath for RequestGroups's Target as_dict override | `observation_portal.requestgroups.models.target_as_dict` |
+| | `REQUESTGROUPS_CONFIGURATION_AS_DICT` | Class dotpath for RequestGroups's Configuration as_dict override | `observation_portal.requestgroups.models.configuration_as_dict` |
+| | `REQUESTGROUPS_LOCATION_AS_DICT` | Class dotpath for RequestGroups's Location as_dict override | `observation_portal.requestgroups.models.location_as_dict` |
+| | `REQUESTGROUPS_WINDOW_AS_DICT` | Class dotpath for RequestGroups's Window as_dict override | `observation_portal.requestgroups.models.window_as_dict` |
+| | `REQUESTGROUPS_REQUEST_AS_DICT` | Class dotpath for RequestGroups's Request as_dict override | `observation_portal.requestgroups.models.request_as_dict` |
+| | `REQUESTGROUPS_REQUESTGROUP_AS_DICT` | Class dotpath for RequestGroups's RequestGroup as_dict override | `observation_portal.requestgroups.models.requestgroup_as_dict` |
+| | `PROPOSALS_PROPOSAL_AS_DICT` | Class dotpath for Proposal's Proposal as_dict override | `observation_portal.proposals.models.proposal_as_dict` |
+| | `PROPOSALS_TIMEALLOCATION_AS_DICT` | Class dotpath for Proposal's TimeAllocation as_dict override | `observation_portal.proposals.models.timeallocation_as_dict` |
+| | `PROPOSALS_MEMBERSHIP_AS_DICT` | Class dotpath for Proposal's Membership as_dict override | `observation_portal.proposals.models.membership_as_dict` |
+| duration Overrides | `INSTRUMENT_CONFIGURATION_PER_EXPOSURE_DURATION` | Class dotpath for duration_per_exposure method override | `observation_portal.requestgroups.duration_utils.get_instrument_configuration_duration_per_exposure` |
+
+
+## Local Development
+
+### **Set up external services**
+
+Please refer to the [Configuration Database](https://github.com/observatorycontrolsystem/configdb) and [Downtime Database](https://github.com/observatorycontrolsystem/downtime) projects for instructions on how to get those running, as well as the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/install-elasticsearch.html) for options on how to run Elasticsearch.
+
+
+### **Poetry**
+
+We use Poetry for package management. If you already have Poetry installed, you
+can skip this section.
+
+You can install Poetry using one of the many options listed at https://python-poetry.org/docs/#installation.
+One simple option is using Pipx:
+
+ python3 -m pip install --user pipx
+ python3 -m pipx ensurepath
+ pipx install poetry
+
+### **Install**
+
+Install the project and its Python dependencies:
+
+ poetry install
+
+This will install the project in a Poetry managed virtual environment. To run
+commands in that environment either use `poetry run ...` or start a shell in
+that environment with `poetry shell`
+
+### **Set up the database**
+
+This example uses the [PostgreSQL Docker image](https://hub.docker.com/_/postgres) to create a database. Make sure that the options that you use to set up your database correspond with your configured database settings.
+
+ docker run --name observation-portal-postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=observation_portal -v/var/lib/postgresql/data -p5432:5432 -d postgres:11.1
+
+After creating the database, migrations must be applied to set up the tables in the database.
+
+ poetry run python manage.py migrate
+
+### **Run the tests**
+
+ poetry run python manage.py test --settings=observation_portal.test_settings
+
+### **Run the portal**
+
+ poetry run python manage.py runserver
+
+The observation portal should now be accessible from <http://127.0.0.1:8000>!
+
+
+%prep
+%autosetup -n django-ocs-observation-portal-4.7.1
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-django-ocs-observation-portal -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Mon May 29 2023 Python_Bot <Python_Bot@openeuler.org> - 4.7.1-1
+- Package Spec generated
diff --git a/sources b/sources
new file mode 100644
index 0000000..391013e
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+39fbbf4f6141b506d7921292ca077e90 django_ocs_observation_portal-4.7.1.tar.gz