diff --git a/.github/actions/build-es6/action.yml b/.github/actions/build-es6/action.yml
deleted file mode 100644
index 5eb71f2147f..00000000000
--- a/.github/actions/build-es6/action.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-name: 'Build ElasticSearch6'
-description: 'Building and starting the ElasticSearch6 service'
-inputs:
- ELASTICSEARCH6_ARCHIVE:
- description: 'Where ES6 archive is located'
-runs:
- using: "composite"
- steps:
- - id: ES6-Step-1
- shell: bash
- run: |
- cd ~/.cache/downloads
- if [ ! -f "${{ inputs.ELASTICSEARCH6_ARCHIVE }}" ]; then
- curl -SLO https://artifacts.elastic.co/downloads/elasticsearch/${{ inputs.ELASTICSEARCH6_ARCHIVE }}
- fi
-
- mkdir -p /tmp/elasticsearch6
- tar -xzf ${{ inputs.ELASTICSEARCH6_ARCHIVE }} -C /tmp/elasticsearch6 --strip-components=1
- echo "ES6 started..."
- - id: ES6-Step-2
- shell: bash
- run: /tmp/elasticsearch6/bin/elasticsearch > /dev/null & export ELASTICSEARCH6_PID=$!
- - id: ES6-Step-3
- shell: bash
- run: |
- echo "Waiting for ES6 health..."
- sleep 5
- while [ ! $(curl -sf http://localhost:9201/_cluster/health?wait_for_status=yellow) ]; do
- echo "trying again...";
- sleep 5;
- done
- echo "ES6 started successfully!"
diff --git a/.github/actions/start-build/action.yml b/.github/actions/start-build/action.yml
index 22d8deae0d5..b75362f56f5 100644
--- a/.github/actions/start-build/action.yml
+++ b/.github/actions/start-build/action.yml
@@ -12,9 +12,6 @@ runs:
- uses: ./.github/actions/build-es
with:
ELASTICSEARCH_ARCHIVE: ${{ env.ELASTICSEARCH_ARCHIVE }}
- - uses: ./.github/actions/build-es6
- with:
- ELASTICSEARCH6_ARCHIVE: ${{ env.ELASTICSEARCH6_ARCHIVE }}
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml
index f147941c5ff..7315f7a4fc0 100644
--- a/.github/workflows/test-build.yml
+++ b/.github/workflows/test-build.yml
@@ -8,7 +8,6 @@ permissions:
env:
WHEELHOUSE: ~/.cache/wheelhouse
ELASTICSEARCH_ARCHIVE: elasticsearch-2.4.5.tar.gz
- ELASTICSEARCH6_ARCHIVE: elasticsearch-6.3.1.tar.gz
OSF_DB_PORT: 5432
OSF_DB_PASSWORD: postgres
GITHUB_ACTIONS: true
@@ -49,6 +48,15 @@ jobs:
--health-interval 10s
--health-timeout 30s
--health-retries 5
+ elasticsearch6: &ES6_SERVICE
+ image: elasticsearch:6.8.23
+ ports:
+ - 9201:9200
+ options: >-
+ --health-cmd "curl -sf http://localhost:9200/_cluster/health?wait_for_status=yellow&timeout=30s"
+ --health-interval 10s
+ --health-timeout 30s
+ --health-retries 5
postgres: &POSTGRES_SERVICE
image: postgres
env:
@@ -68,6 +76,7 @@ jobs:
run: poetry run python3 -m invoke test-ci-addons --junit
env:
ELASTIC8_URI: http://localhost:9202
+ ELASTIC6_URI: http://localhost:9201
- name: Upload report
if: (success() || failure()) # run this step even if previous step failed
uses: ./.github/actions/gen-report
@@ -95,6 +104,7 @@ jobs:
checks: write
services:
elasticsearch8: *ES8_SERVICE
+ elasticsearch6: *ES6_SERVICE
postgres: *POSTGRES_SERVICE
steps:
- uses: actions/checkout@v6
@@ -105,6 +115,7 @@ jobs:
run: poetry run python3 -m invoke test-ci-api1-and-js --junit
env:
ELASTIC8_URI: http://localhost:9202
+ ELASTIC6_URI: http://localhost:9201
- name: Upload report
if: (success() || failure()) # run this step even if previous step failed
uses: ./.github/actions/gen-report
@@ -116,6 +127,7 @@ jobs:
checks: write
services:
elasticsearch8: *ES8_SERVICE
+ elasticsearch6: *ES6_SERVICE
postgres: *POSTGRES_SERVICE
steps:
- uses: actions/checkout@v6
@@ -124,6 +136,7 @@ jobs:
run: poetry run python3 -m invoke test-ci-api2 --junit
env:
ELASTIC8_URI: http://localhost:9202
+ ELASTIC6_URI: http://localhost:9201
- name: Upload report
if: (success() || failure()) # run this step even if previous step failed
uses: ./.github/actions/gen-report
@@ -140,6 +153,9 @@ jobs:
- uses: ./.github/actions/start-build
- name: Run tests
run: poetry run python3 -m invoke test-ci-api3-and-osf --junit
+ env:
+ ELASTIC8_URI: http://localhost:9202
+ ELASTIC6_URI: http://localhost:9201
- name: Upload report
if: (success() || failure()) # run this step even if previous step failed
uses: ./.github/actions/gen-report
diff --git a/CHANGELOG b/CHANGELOG
index 4ec4deff59e..0863d2c773a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,40 @@
We follow the CalVer (https://calver.org/) versioning scheme: YY.MINOR.MICRO.
+26.13.0 (2026-07-01)
+====================
+
+- add migrate_osfmetrics_fix_6to8 command to correct monthly usage reports
+- temporarily re-add elasticsearch6 and some es6-based osf-metrics models
+
+
+26.12.0 (2026-06-23)
+====================
+
+- ES2 Consolidation
+
+26.11.0 (2026-06-10)
+====================
+
+- Stop using elasticsearch6
+- Change all osfmetrics-consuming code to use es8 from data migration in 26.10.0
+
+
+26.10.7 (2026-06-10)
+====================
+
+- Fix typo in pyproject.toml
+
+26.10.6 (2026-06-10)
+====================
+
+- Disable Preprint DELETE from API
+
+26.10.5 (2026-06-09)
+====================
+
+- Prevent users from using URLs/domains in their names
+
26.10.4 (2026-06-04)
====================
diff --git a/README-docker-compose.md b/README-docker-compose.md
index 0956379333f..6cc0f0341b3 100644
--- a/README-docker-compose.md
+++ b/README-docker-compose.md
@@ -116,11 +116,7 @@
#### Special Instructions for Apple Chipset (M1, M2, etc.) and other ARM64 architecture
- * _NOTE: The default `elasticsearch`, `elasticsearch6`, and `sharejs` containers are incompatible with ARM64._
-
- - To run `elasticsearch6` on ARM64 architecture:
-
- - Copy `docker-compose-dist-arm64.override.yml` into your `docker-compose.override.yml` file
+ * _NOTE: The default `elasticsearch` and `sharejs` containers are incompatible with ARM64._
- Running containers with docker compose
@@ -194,7 +190,7 @@
- Start all containers
```bash
- alias dcsa="docker compose up -d assets admin_assets mfr wb fakecas sharejs worker elasticsearch elasticsearch6 web api admin preprints gv"
+ alias dcsa="docker compose up -d assets admin_assets mfr wb fakecas sharejs worker elasticsearch elasticsearch8 web api admin preprints gv"
```
- Shut down all containers
diff --git a/addons/base/views.py b/addons/base/views.py
index 12b78fb9957..04e620c4c54 100644
--- a/addons/base/views.py
+++ b/addons/base/views.py
@@ -14,7 +14,7 @@
import waffle
from django.db import transaction
from django.contrib.contenttypes.models import ContentType
-from elasticsearch6 import exceptions as es_exceptions
+from elasticsearch8 import exceptions as es_exceptions
from rest_framework import status as http_status
from api.caching.tasks import update_storage_usage_with_size
@@ -34,7 +34,7 @@
from framework.flask import redirect
from framework.sentry import log_exception
from framework.transactions.handlers import no_auto_transaction
-from osf.metrics.es8_metrics import OsfCountedUsageEvent
+from osf.metrics.events import OsfCountedUsageEvent
from website import settings
from addons.base import signals as file_signals
from addons.base.utils import format_last_known_metadata, get_mfr_url
@@ -54,7 +54,6 @@
FileVersionUserMetadata,
FileVersion, NotificationTypeEnum
)
-from osf.metrics import PreprintView, PreprintDownload
from osf.utils import permissions
from osf.external.gravy_valet import request_helpers
from website.profile.utils import get_profile_image_url
@@ -686,12 +685,6 @@ def osfstoragefile_viewed_update_metrics(self, auth, fileversion, file_node):
return
if waffle.switch_is_active(features.ELASTICSEARCH_METRICS) and isinstance(resource, Preprint):
try:
- PreprintView.record_for_preprint(
- preprint=resource,
- user=auth.user,
- version=fileversion.identifier,
- path=file_node.path,
- )
OsfCountedUsageEvent.record(
user_id=getattr(user, '_id', None),
item_osfid=resource._id,
@@ -725,12 +718,6 @@ def osfstoragefile_downloaded_update_metrics(self, auth, fileversion, file_node)
return
if waffle.switch_is_active(features.ELASTICSEARCH_METRICS) and isinstance(resource, Preprint):
try:
- PreprintDownload.record_for_preprint(
- preprint=resource,
- user=auth.user,
- version=fileversion.identifier,
- path=file_node.path,
- )
OsfCountedUsageEvent.record(
user_id=getattr(user, '_id', None),
item_osfid=resource._id,
diff --git a/admin/base/utils.py b/admin/base/utils.py
index f0159204863..a612e06c185 100644
--- a/admin/base/utils.py
+++ b/admin/base/utils.py
@@ -1,7 +1,7 @@
"""
Utility functions and classes
"""
-from osf.models import Subject, NodeLicense, Brand
+from osf.models import Subject, NodeLicense, Brand, CedarMetadataTemplate
from django.core.exceptions import ValidationError, PermissionDenied
from django.urls import reverse
@@ -116,6 +116,11 @@ def get_brand_choices():
brands = Brand.objects.all()
return [no_default] + [(brand.id, brand.name) for brand in brands]
+def get_cedar_template_choices():
+ no_default = ('', '---------')
+ templates = CedarMetadataTemplate.objects.filter(active=True)
+ return [no_default] + [(t.id, t.schema_name) for t in templates]
+
def get_toplevel_subjects():
return Subject.objects.filter(parent__isnull=True, provider___id='osf').values_list('id', 'text')
diff --git a/admin/cedar/forms.py b/admin/cedar/forms.py
index f430be3cb4d..e446dde4196 100644
--- a/admin/cedar/forms.py
+++ b/admin/cedar/forms.py
@@ -1,7 +1,8 @@
-from django.forms import ModelForm, CharField, JSONField
+from django.forms import ModelForm, CharField, JSONField, BooleanField
from osf.models import CedarMetadataTemplate
+
class CedarMetadataTemplateForm(ModelForm):
schema_name = CharField(
disabled=True,
@@ -18,7 +19,8 @@ class CedarMetadataTemplateForm(ModelForm):
template = JSONField(
disabled=True
)
+ is_for_collections = BooleanField(label='For collections only:', required=False)
class Meta:
model = CedarMetadataTemplate
- fields = ['schema_name', 'cedar_id', 'template_version', 'template', 'active']
+ fields = ['schema_name', 'cedar_id', 'template_version', 'template', 'is_for_collections', 'active', 'should_index_for_search']
diff --git a/admin/collection_providers/forms.py b/admin/collection_providers/forms.py
index 7d0e8dadf46..c190f9af9dd 100644
--- a/admin/collection_providers/forms.py
+++ b/admin/collection_providers/forms.py
@@ -4,7 +4,7 @@
from framework.utils import sanitize_html
from osf.models import CollectionProvider
-from admin.base.utils import get_nodelicense_choices, get_defaultlicense_choices, validate_slug
+from admin.base.utils import get_nodelicense_choices, get_defaultlicense_choices, validate_slug, get_cedar_template_choices
class CollectionProviderForm(forms.ModelForm):
@@ -37,9 +37,11 @@ class Meta:
def __init__(self, *args, **kwargs):
nodelicense_choices = get_nodelicense_choices()
defaultlicense_choices = get_defaultlicense_choices()
+ cedar_template_choices = get_cedar_template_choices()
super().__init__(*args, **kwargs)
self.fields['licenses_acceptable'].choices = nodelicense_choices
self.fields['default_license'].choices = defaultlicense_choices
+ self.fields['required_metadata_template'].choices = cedar_template_choices
def clean_description(self, *args, **kwargs):
if not self.data.get('description'):
diff --git a/admin/collection_providers/views.py b/admin/collection_providers/views.py
index 779f7b89c04..ac9efd0e935 100644
--- a/admin/collection_providers/views.py
+++ b/admin/collection_providers/views.py
@@ -132,127 +132,78 @@ def get_context_data(self, *args, **kwargs):
licenses_html += ''
collection_provider_attributes['licenses_acceptable'] = licenses_html
- primary_collection = collection_provider.primary_collection
- # compile html list of collected_type_choices
- collected_type_choices_html = '
'
- for choice in primary_collection.collected_type_choices:
- collected_type_choices_html += f'- {choice}
'
- collected_type_choices_html += '
'
- kwargs['collected_type_choices'] = collected_type_choices_html
-
- # compile html list of status_choices
- status_choices_html = ''
- for choice in primary_collection.status_choices:
- status_choices_html += f'- {choice}
'
- status_choices_html += '
'
- kwargs['status_choices'] = status_choices_html
-
- # compile html list of volume_choices
- volume_choices_html = ''
- for choice in primary_collection.volume_choices:
- volume_choices_html += f'- {choice}
'
- volume_choices_html += '
'
- kwargs['volume_choices'] = volume_choices_html
-
- # compile html list of issue_choices
- issue_choices_html = ''
- for choice in primary_collection.issue_choices:
- issue_choices_html += f'- {choice}
'
- issue_choices_html += '
'
- kwargs['issue_choices'] = issue_choices_html
-
- # compile html list of program_area_choices
- program_area_choices_html = ''
- for choice in primary_collection.program_area_choices:
- program_area_choices_html += f'- {choice}
'
- program_area_choices_html += '
'
- kwargs['program_area_choices'] = program_area_choices_html
-
- # compile html list of school_type_choices
- school_type_choices_html = ''.format(choices=''.join(
- f'{choice}' for choice in primary_collection.school_type_choices
- ))
- kwargs['school_type_choices'] = school_type_choices_html
-
- # compile html list of study_design_choices
- study_design_choices_html = ''.format(choices=''.join(
- f'{choice}' for choice in primary_collection.study_design_choices
- ))
- kwargs['study_design_choices'] = study_design_choices_html
-
- disease_choices_html = ''.format(choices=''.join(
- f'{choice}' for choice in primary_collection.disease_choices
- ))
- kwargs['disease_choices'] = disease_choices_html
-
- data_type_choices_html = ''.format(choices=''.join(
- f'{choice}' for choice in primary_collection.data_type_choices
- ))
- kwargs['data_type_choices'] = data_type_choices_html
-
- grade_levels_choices_html = ''.format(choices=''.join(
- f'{choice}' for choice in primary_collection.grade_levels_choices
- ))
- kwargs['grade_levels_choices'] = grade_levels_choices_html
-
- # get a dict of model fields so that we can set the initial value for the update form
fields = model_to_dict(collection_provider)
- fields['collected_type_choices'] = json.dumps(primary_collection.collected_type_choices)
- fields['status_choices'] = json.dumps(primary_collection.status_choices)
- fields['volume_choices'] = json.dumps(primary_collection.volume_choices)
- fields['issue_choices'] = json.dumps(primary_collection.issue_choices)
- fields['program_area_choices'] = json.dumps(primary_collection.program_area_choices)
- fields = model_to_dict(collection_provider)
-
- fields['school_type_choices'] = json.dumps(primary_collection.school_type_choices)
- fields['study_design_choices'] = json.dumps(primary_collection.study_design_choices)
- fields['data_type_choices'] = json.dumps(primary_collection.data_type_choices)
- fields['disease_choices'] = json.dumps(primary_collection.disease_choices)
- fields['grade_levels_choices'] = json.dumps(primary_collection.grade_levels_choices)
-
- # compile html list of collected_type_choices
if collection_provider.primary_collection:
+ primary_collection = collection_provider.primary_collection
+
+ # compile html list of collected_type_choices
collected_type_choices_html = ''
- for choice in collection_provider.primary_collection.collected_type_choices:
+ for choice in primary_collection.collected_type_choices:
collected_type_choices_html += f'- {choice}
'
collected_type_choices_html += '
'
kwargs['collected_type_choices'] = collected_type_choices_html
# compile html list of status_choices
status_choices_html = ''
- for choice in collection_provider.primary_collection.status_choices:
+ for choice in primary_collection.status_choices:
status_choices_html += f'- {choice}
'
status_choices_html += '
'
kwargs['status_choices'] = status_choices_html
# compile html list of volume_choices
volume_choices_html = ''
- for choice in collection_provider.primary_collection.volume_choices:
+ for choice in primary_collection.volume_choices:
volume_choices_html += f'- {choice}
'
volume_choices_html += '
'
kwargs['volume_choices'] = volume_choices_html
# compile html list of issue_choices
issue_choices_html = ''
- for choice in collection_provider.primary_collection.issue_choices:
+ for choice in primary_collection.issue_choices:
issue_choices_html += f'- {choice}
'
issue_choices_html += '
'
kwargs['issue_choices'] = issue_choices_html
# compile html list of program_area_choices
program_area_choices_html = ''
- for choice in collection_provider.primary_collection.program_area_choices:
+ for choice in primary_collection.program_area_choices:
program_area_choices_html += f'- {choice}
'
program_area_choices_html += '
'
kwargs['program_area_choices'] = program_area_choices_html
- # get a dict of model fields so that we can set the initial value for the update form
- fields['collected_type_choices'] = json.dumps(collection_provider.primary_collection.collected_type_choices)
- fields['status_choices'] = json.dumps(collection_provider.primary_collection.status_choices)
- fields['volume_choices'] = json.dumps(collection_provider.primary_collection.volume_choices)
- fields['issue_choices'] = json.dumps(collection_provider.primary_collection.issue_choices)
- fields['program_area_choices'] = json.dumps(collection_provider.primary_collection.program_area_choices)
+ # compile html list of school_type_choices
+ kwargs['school_type_choices'] = ''.format(choices=''.join(
+ f'{choice}' for choice in primary_collection.school_type_choices
+ ))
+
+ # compile html list of study_design_choices
+ kwargs['study_design_choices'] = ''.format(choices=''.join(
+ f'{choice}' for choice in primary_collection.study_design_choices
+ ))
+
+ kwargs['disease_choices'] = ''.format(choices=''.join(
+ f'{choice}' for choice in primary_collection.disease_choices
+ ))
+
+ kwargs['data_type_choices'] = ''.format(choices=''.join(
+ f'{choice}' for choice in primary_collection.data_type_choices
+ ))
+
+ kwargs['grade_levels_choices'] = ''.format(choices=''.join(
+ f'{choice}' for choice in primary_collection.grade_levels_choices
+ ))
+
+ fields['collected_type_choices'] = json.dumps(primary_collection.collected_type_choices)
+ fields['status_choices'] = json.dumps(primary_collection.status_choices)
+ fields['volume_choices'] = json.dumps(primary_collection.volume_choices)
+ fields['issue_choices'] = json.dumps(primary_collection.issue_choices)
+ fields['program_area_choices'] = json.dumps(primary_collection.program_area_choices)
+ fields['school_type_choices'] = json.dumps(primary_collection.school_type_choices)
+ fields['study_design_choices'] = json.dumps(primary_collection.study_design_choices)
+ fields['data_type_choices'] = json.dumps(primary_collection.data_type_choices)
+ fields['disease_choices'] = json.dumps(primary_collection.disease_choices)
+ fields['grade_levels_choices'] = json.dumps(primary_collection.grade_levels_choices)
kwargs['form'] = CollectionProviderForm(initial=fields)
@@ -272,7 +223,7 @@ def form_valid(self, form):
if self.object.primary_collection:
for choices_name in ['collected_type', 'status', 'issue', 'volume', 'program_area', 'school_type', 'study_design', 'data_type', 'disease', 'grade_levels']:
_process_collection_choices(self.object, choices_name, form)
- self.object.primary_collection.save()
+ self.object.primary_collection.save()
return super().form_valid(form)
def form_invalid(self, form):
diff --git a/admin/management/urls.py b/admin/management/urls.py
index 2e4cd7479a1..851227efafa 100644
--- a/admin/management/urls.py
+++ b/admin/management/urls.py
@@ -22,5 +22,5 @@
name='sync_notification_templates'),
re_path(r'^remove_orcid_from_user_social', views.RemoveOrcidFromUserSocial.as_view(),
name='remove_orcid_from_user_social'),
- path('migrate_osfmetrics_6to8', views.MigrateOsfmetrics6to8.as_view(), name='migrate_osfmetrics_6to8'),
+ path('migrate_osfmetrics_fix_6to8', views.MigrateOsfmetricsFix6to8.as_view(), name='migrate_osfmetrics_fix_6to8'),
]
diff --git a/admin/management/views.py b/admin/management/views.py
index c1bdf19f333..cd2ad98e94c 100644
--- a/admin/management/views.py
+++ b/admin/management/views.py
@@ -217,20 +217,16 @@ def post(self, request):
return redirect(reverse('management:commands'))
-class MigrateOsfmetrics6to8(ManagementCommandPermissionView):
+class MigrateOsfmetricsFix6to8(ManagementCommandPermissionView):
def post(self, request):
_command_kwargs = {
'no_color': True,
'no_counts': request.POST.get('no_counts'),
- 'clear_state': request.POST.get('clear_state'),
- 'clear_es8_data': request.POST.get('clear_es8_data'),
+ 'delete_es8_usage_reports': request.POST.get('delete_es8_usage_reports'),
'start': request.POST.get('start'),
- 'unchanged': request.POST.get('unchanged'),
- 'usage_reports': request.POST.get('usage_reports'),
- 'usage_events': request.POST.get('usage_events'),
}
_out_io = StringIO()
- call_command('migrate_osfmetrics_6to8', **_command_kwargs, stdout=_out_io)
+ call_command('migrate_osfmetrics_fix_6to8', **_command_kwargs, stdout=_out_io)
for _line in _out_io.getvalue().split('\n'):
messages.info(request, _line)
return redirect(reverse('management:commands'))
diff --git a/admin/preprint_providers/forms.py b/admin/preprint_providers/forms.py
index cb7a0f1b1e9..cee414b4815 100644
--- a/admin/preprint_providers/forms.py
+++ b/admin/preprint_providers/forms.py
@@ -8,7 +8,8 @@
Subject
)
from admin.base.utils import (get_subject_rules, get_toplevel_subjects,
- get_nodelicense_choices, get_defaultlicense_choices, validate_slug)
+ get_nodelicense_choices, get_defaultlicense_choices, validate_slug,
+ get_cedar_template_choices)
class PreprintProviderForm(forms.ModelForm):
@@ -42,10 +43,12 @@ def __init__(self, *args, **kwargs):
toplevel_choices = get_toplevel_subjects()
nodelicense_choices = get_nodelicense_choices()
defaultlicense_choices = get_defaultlicense_choices()
+ cedar_template_choices = get_cedar_template_choices()
super().__init__(*args, **kwargs)
self.fields['toplevel_subjects'].choices = toplevel_choices
self.fields['licenses_acceptable'].choices = nodelicense_choices
self.fields['default_license'].choices = defaultlicense_choices
+ self.fields['required_metadata_template'].choices = cedar_template_choices
def clean_subjects_acceptable(self, *args, **kwargs):
subject_ids = [_f for _f in self.data['subjects_chosen'].split(', ') if _f]
diff --git a/admin/registration_providers/forms.py b/admin/registration_providers/forms.py
index dffda09e455..3bae6aa9a09 100644
--- a/admin/registration_providers/forms.py
+++ b/admin/registration_providers/forms.py
@@ -7,6 +7,7 @@
get_defaultlicense_choices,
validate_slug,
get_brand_choices,
+ get_cedar_template_choices,
)
@@ -41,10 +42,12 @@ def __init__(self, *args, **kwargs):
nodelicense_choices = get_nodelicense_choices()
defaultlicense_choices = get_defaultlicense_choices()
brand_choices = get_brand_choices()
+ cedar_template_choices = get_cedar_template_choices()
super().__init__(*args, **kwargs)
self.fields['licenses_acceptable'].choices = nodelicense_choices
self.fields['default_license'].choices = defaultlicense_choices
self.fields['brand'].choices = brand_choices
+ self.fields['required_metadata_template'].choices = cedar_template_choices
if kwargs.get('initial', None) and kwargs.get('initial').get('_id', None):
provider = RegistrationProvider.load(kwargs.get('initial').get('_id'))
self.fields['default_schema'].choices = provider.schemas.filter(visible=True, active=True).values_list('id', 'name')
diff --git a/admin/templates/cedar/list.html b/admin/templates/cedar/list.html
index 9d089714e50..0717d1c342b 100644
--- a/admin/templates/cedar/list.html
+++ b/admin/templates/cedar/list.html
@@ -14,6 +14,7 @@ List of Cedar Metadata Templates
Name |
Version |
Active |
+ For Collections only |
@@ -33,6 +34,9 @@ List of Cedar Metadata Templates
{{ template.active }}
|
+
+ {{ template.is_for_collections }}
+ |
{% endfor %}
diff --git a/admin/templates/management/commands.html b/admin/templates/management/commands.html
index 799a7430cf2..28c8047083d 100644
--- a/admin/templates/management/commands.html
+++ b/admin/templates/management/commands.html
@@ -201,25 +201,17 @@ Remove existing orcid info from user social
- migrate osf-metrics 6to8
+ migrate osf-metrics (fix) 6to8
- view progress of the osf-metrics migration from elastic6 to elastic8 (or start it)
+ view progress of the osf-metrics migration (fixup) from elastic6 to elastic8 (or start it)