Skip to content

Commit 179bed0

Browse files
Add SSO availability field and update institution reactivation logic
1 parent 7a54304 commit 179bed0

5 files changed

Lines changed: 55 additions & 21 deletions

File tree

admin_tests/institutions/test_views.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ def test_institution_form(self):
139139
'name': 'New Name',
140140
'logo_name': 'awesome_logo.png',
141141
'domains': 'http://kris.biz/, http://www.little.biz/',
142-
'_id': 'newawesomeprov'
142+
'_id': 'newawesomeprov',
143+
'sso_availability': 'Public',
143144
}
144145
form = InstitutionForm(data=new_data)
145146
assert form.is_valid()
@@ -214,7 +215,8 @@ def test_monthly_reporter_called_on_create(self, mock_monthly_reporter_do):
214215
'email_domains': FakeList('domain_name', n=1),
215216
'orcid_record_verified_source': '',
216217
'delegation_protocol': '',
217-
'institutional_request_access_enabled': False
218+
'institutional_request_access_enabled': False,
219+
'sso_availability': 'Public',
218220
}
219221
form = InstitutionForm(data=data)
220222
assert form.is_valid()

osf/migrations/0036_institution_sso_in_progress.py

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.2.15 on 2026-03-13 11:11
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('osf', '0037_notification_refactor_post_release'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='institution',
15+
name='sso_availability',
16+
field=models.CharField(choices=[('Public', 'PUBLIC'), ('Unavailable', 'UNAVAILABLE'), ('Hidden', 'HIDDEN')], default='Hidden', max_length=15),
17+
),
18+
]

osf/models/institution.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ class SsoFilterCriteriaAction(Enum):
4646
CONTAINS = 'contains' # Type 2: SSO releases a multi-value attribute, of which one value matches
4747
IN = 'in' # Type 3: SSO releases a single-value attribute that have multiple valid values
4848

49+
class SSOAvailability(Enum):
50+
"""Defines 3 SSO availability states for institutions.
51+
"""
52+
PUBLIC = 'Public'
53+
UNAVAILABLE = 'Unavailable'
54+
HIDDEN = 'Hidden'
55+
4956

5057
class InstitutionManager(models.Manager):
5158

@@ -79,6 +86,13 @@ class Institution(DirtyFieldsMixin, Loggable, ObjectIDMixin, BaseModel, Guardian
7986
default=''
8087
)
8188

89+
# Institution SSO availability
90+
sso_availability = models.CharField(
91+
choices=[(el.value, el.name) for el in SSOAvailability],
92+
max_length=15,
93+
default='Hidden'
94+
)
95+
8296
# Default Storage Region
8397
storage_regions = models.ManyToManyField(
8498
'addons_osfstorage.Region',
@@ -125,7 +139,6 @@ class Institution(DirtyFieldsMixin, Loggable, ObjectIDMixin, BaseModel, Guardian
125139
default='',
126140
help_text='Full URL where institutional admins can access archived metrics reports.',
127141
)
128-
sso_in_progress = models.BooleanField(default=False)
129142

130143
class Meta:
131144
# custom permissions for use in the OSF Admin App
@@ -238,6 +251,11 @@ def deactivate(self):
238251
"""
239252
if not self.deactivated:
240253
self.deactivated = timezone.now()
254+
if not self.delegation_protocol:
255+
self.sso_availability = SSOAvailability.UNAVAILABLE.value
256+
else:
257+
self.sso_availability = SSOAvailability.HIDDEN.value
258+
241259
self.save()
242260
# Django mangers aren't used when querying on related models. Thus, we can query
243261
# affiliated users and send notification emails after the institution has been deactivated.
@@ -252,6 +270,10 @@ def reactivate(self):
252270
"""
253271
if self.deactivated:
254272
self.deactivated = None
273+
if not self.delegation_protocol:
274+
self.sso_availability = SSOAvailability.UNAVAILABLE.value
275+
else:
276+
self.sso_availability = SSOAvailability.HIDDEN.value
255277
self.save()
256278
else:
257279
message = f'Action rejected - reactivating an active institution [{self._id}].'

osf_tests/test_institution.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,22 @@ def test_deactivate_institution(self):
139139
assert institution.deactivated is not None
140140
assert mock__send_deactivation_email.called
141141

142+
def test_reactivate_sso_institution(self):
143+
institution = InstitutionFactory()
144+
institution.delegation_protocol = 'saml-shib'
145+
institution.deactivated = timezone.now()
146+
institution.save()
147+
institution.reactivate()
148+
assert institution.deactivated is None
149+
assert institution.sso_availability == 'Hidden'
150+
142151
def test_reactivate_institution(self):
143152
institution = InstitutionFactory()
144153
institution.deactivated = timezone.now()
145154
institution.save()
146155
institution.reactivate()
147156
assert institution.deactivated is None
157+
assert institution.sso_availability == 'Unavailable'
148158

149159
def test_send_deactivation_email_call_count(self):
150160
institution = InstitutionFactory()

0 commit comments

Comments
 (0)