From ec7427822ebabb38312e76c994e22bf6d3291d84 Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 22 May 2026 16:58:09 +0200 Subject: [PATCH 1/4] feat: Add CLIENT_ID_REGISTRATION_PAUSED to config service --- app/services/config-service.js | 3 ++- config/environment.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/services/config-service.js b/app/services/config-service.js index 81c2f127..96b72a47 100644 --- a/app/services/config-service.js +++ b/app/services/config-service.js @@ -2,5 +2,6 @@ import Service from '@ember/service'; import config from '../config/environment'; export default Service.extend({ - API_URL: config.API_URL + API_URL: config.API_URL, + CLIENT_ID_REGISTRATION_PAUSED: config.CLIENT_ID_REGISTRATION_PAUSED }); \ No newline at end of file diff --git a/config/environment.js b/config/environment.js index 05974657..3578d1b7 100644 --- a/config/environment.js +++ b/config/environment.js @@ -20,6 +20,7 @@ module.exports = function(environment) { }, API_URL: process.env.API_URL || "https://api.ror.org/v2", + CLIENT_ID_REGISTRATION_PAUSED: true, BASE_URL: process.env.BASE_URL || null, SENTRY_DSN: process.env.SENTRY_DSN || null, VERSION: pkg.version, From 851dbbbefd7813ff0dad059cd272496c1ee4fe7f Mon Sep 17 00:00:00 2001 From: jrhoads Date: Fri, 22 May 2026 16:58:58 +0200 Subject: [PATCH 2/4] feat: Disable API client registration when paused --- .../api-client-registration-form.hbs | 7 ++++++- .../api-client-registration-form.js | 10 +++++++++- app/routes/organizations/api-client-id.js | 10 +++++++++- .../api-client-registration-form.scss | 5 +++++ app/templates/organizations/api-client-id.hbs | 19 +++++++++++++++++-- 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/app/components/organizations/api-client-registration-form.hbs b/app/components/organizations/api-client-registration-form.hbs index 3cf525a8..e728db44 100644 --- a/app/components/organizations/api-client-registration-form.hbs +++ b/app/components/organizations/api-client-registration-form.hbs @@ -1,4 +1,4 @@ -
+
{{#if this.showSuccessMessage}}

Thank you for registering!

@@ -59,6 +59,7 @@ required aria-invalid={{if this.emailError "true" "false"}} aria-describedby={{if this.emailError "email-error"}} + disabled={{@registrationPaused}} {{on "blur" (fn this.validateField "email" this.email)}} /> {{#if this.emailError}} @@ -79,6 +80,7 @@ {{#if this.nameError}} @@ -101,6 +103,7 @@ @matchTriggerWidth={{true}} @ariaDescribedBy={{if this.institutionError "institution-error"}} @ariaInvalid={{if this.institutionError "true" "false"}} + @disabled={{@registrationPaused}} class={{if this.institutionError "is-invalid"}} as |institution|> {{#if institution.name}} @@ -129,6 +132,7 @@ @matchTriggerWidth={{true}} @ariaDescribedBy={{if this.countryError "country-error"}} @ariaInvalid={{if this.countryError "true" "false"}} + @disabled={{@registrationPaused}} class={{if this.countryError "is-invalid"}} as |country|> {{country.name}} ({{country.code}}) @@ -151,6 +155,7 @@ {{#if this.rorUseError}} diff --git a/app/components/organizations/api-client-registration-form.js b/app/components/organizations/api-client-registration-form.js index 536e51ce..301ca7c3 100644 --- a/app/components/organizations/api-client-registration-form.js +++ b/app/components/organizations/api-client-registration-form.js @@ -29,7 +29,7 @@ export default class ApiClientRegistrationFormComponent extends Component { countries = countries; get isFormInvalid() { - return this.hasValidationErrors || !this.email || this.isSubmitting; + return this.args.registrationPaused || this.hasValidationErrors || !this.email || this.isSubmitting; } get hasValidationErrors() { @@ -214,6 +214,10 @@ export default class ApiClientRegistrationFormComponent extends Component { @action onSubmit() { + if (this.args.registrationPaused) { + return; + } + this.emailError = this.validateEmail(this.email); this.nameError = this.validateName(this.name); this.institutionError = this.validateInstitution(this.institution_name); @@ -253,6 +257,10 @@ export default class ApiClientRegistrationFormComponent extends Component { } async _SubmitForm() { + if (this.args.registrationPaused) { + return; + } + this.isSubmitting = true; this.showErrorMessage = false; diff --git a/app/routes/organizations/api-client-id.js b/app/routes/organizations/api-client-id.js index 58b40ed2..f49afde9 100644 --- a/app/routes/organizations/api-client-id.js +++ b/app/routes/organizations/api-client-id.js @@ -1,4 +1,12 @@ import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; export default class OrganizationsRegisterRoute extends Route { -} \ No newline at end of file + @service('config-service') configService; + + model() { + return { + registrationPaused: this.configService.CLIENT_ID_REGISTRATION_PAUSED, + }; + } +} diff --git a/app/styles/components/organizations/api-client-registration-form.scss b/app/styles/components/organizations/api-client-registration-form.scss index 4c94421a..e22dc5d2 100644 --- a/app/styles/components/organizations/api-client-registration-form.scss +++ b/app/styles/components/organizations/api-client-registration-form.scss @@ -1,5 +1,10 @@ /* app/styles/components/organizations/api-client-registration-form.scss */ .api-client-registration-form { + &--paused { + opacity: 0.65; + pointer-events: none; + } + // Input and Textarea base styles .form-control { border: 1px solid #312d2d; diff --git a/app/templates/organizations/api-client-id.hbs b/app/templates/organizations/api-client-id.hbs index bac7c1b1..cc893ebf 100644 --- a/app/templates/organizations/api-client-id.hbs +++ b/app/templates/organizations/api-client-id.hbs @@ -6,7 +6,9 @@

ROR API users are encouraged to register for a client ID and to include it in the header of API requests. Requests that include a header named client-id with a valid client ID as its value will receive a rate limit of 2,000 requests/5min. API requests that don't include a client ID will receive a rate limit of 50 requests/5min.

-

Please complete the form below to register for a ROR API client ID. Your client ID will be sent to the email address you provide.

+ {{#unless this.model.registrationPaused}} +

Please complete the form below to register for a ROR API client ID. Your client ID will be sent to the email address you provide.

+ {{/unless}}

A few notes about ROR API client IDs:

    @@ -20,6 +22,19 @@
- + {{#if this.model.registrationPaused}} + + Client ID registration is temporarily paused. +

We've paused new ROR API client ID registrations while we make updates to the service. No rate limits + are currently enforced based on the presence or absence of a client ID, and none will be introduced before + registration is restored, so API usage is not affected by this pause. +

+

+ If you have questions or an urgent request, please contact support@ror.org. + Thanks for your patience!

+
+ {{/if}} + +
From f3885718399adc34bbef376406abb414dcc10833 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 22 May 2026 09:00:26 -0700 Subject: [PATCH 3/4] Hide registration form when paused to avoid accessibility issues and clean up banner layout --- .../api-client-registration-form.hbs | 7 +---- .../api-client-registration-form.js | 10 +----- .../api-client-registration-form.scss | 5 --- app/templates/organizations/api-client-id.hbs | 31 +++++++++---------- tests/acceptance/a11y/api-client-test.js | 12 +++++-- tests/acceptance/api-client-id-test.js | 28 +++++++++++++++++ tests/test-helper.js | 4 +++ 7 files changed, 59 insertions(+), 38 deletions(-) create mode 100644 tests/acceptance/api-client-id-test.js diff --git a/app/components/organizations/api-client-registration-form.hbs b/app/components/organizations/api-client-registration-form.hbs index e728db44..3cf525a8 100644 --- a/app/components/organizations/api-client-registration-form.hbs +++ b/app/components/organizations/api-client-registration-form.hbs @@ -1,4 +1,4 @@ -
+
{{#if this.showSuccessMessage}}

Thank you for registering!

@@ -59,7 +59,6 @@ required aria-invalid={{if this.emailError "true" "false"}} aria-describedby={{if this.emailError "email-error"}} - disabled={{@registrationPaused}} {{on "blur" (fn this.validateField "email" this.email)}} /> {{#if this.emailError}} @@ -80,7 +79,6 @@ {{#if this.nameError}} @@ -103,7 +101,6 @@ @matchTriggerWidth={{true}} @ariaDescribedBy={{if this.institutionError "institution-error"}} @ariaInvalid={{if this.institutionError "true" "false"}} - @disabled={{@registrationPaused}} class={{if this.institutionError "is-invalid"}} as |institution|> {{#if institution.name}} @@ -132,7 +129,6 @@ @matchTriggerWidth={{true}} @ariaDescribedBy={{if this.countryError "country-error"}} @ariaInvalid={{if this.countryError "true" "false"}} - @disabled={{@registrationPaused}} class={{if this.countryError "is-invalid"}} as |country|> {{country.name}} ({{country.code}}) @@ -155,7 +151,6 @@ {{#if this.rorUseError}} diff --git a/app/components/organizations/api-client-registration-form.js b/app/components/organizations/api-client-registration-form.js index 301ca7c3..536e51ce 100644 --- a/app/components/organizations/api-client-registration-form.js +++ b/app/components/organizations/api-client-registration-form.js @@ -29,7 +29,7 @@ export default class ApiClientRegistrationFormComponent extends Component { countries = countries; get isFormInvalid() { - return this.args.registrationPaused || this.hasValidationErrors || !this.email || this.isSubmitting; + return this.hasValidationErrors || !this.email || this.isSubmitting; } get hasValidationErrors() { @@ -214,10 +214,6 @@ export default class ApiClientRegistrationFormComponent extends Component { @action onSubmit() { - if (this.args.registrationPaused) { - return; - } - this.emailError = this.validateEmail(this.email); this.nameError = this.validateName(this.name); this.institutionError = this.validateInstitution(this.institution_name); @@ -257,10 +253,6 @@ export default class ApiClientRegistrationFormComponent extends Component { } async _SubmitForm() { - if (this.args.registrationPaused) { - return; - } - this.isSubmitting = true; this.showErrorMessage = false; diff --git a/app/styles/components/organizations/api-client-registration-form.scss b/app/styles/components/organizations/api-client-registration-form.scss index e22dc5d2..4c94421a 100644 --- a/app/styles/components/organizations/api-client-registration-form.scss +++ b/app/styles/components/organizations/api-client-registration-form.scss @@ -1,10 +1,5 @@ /* app/styles/components/organizations/api-client-registration-form.scss */ .api-client-registration-form { - &--paused { - opacity: 0.65; - pointer-events: none; - } - // Input and Textarea base styles .form-control { border: 1px solid #312d2d; diff --git a/app/templates/organizations/api-client-id.hbs b/app/templates/organizations/api-client-id.hbs index cc893ebf..1dec6dba 100644 --- a/app/templates/organizations/api-client-id.hbs +++ b/app/templates/organizations/api-client-id.hbs @@ -18,23 +18,22 @@
  • For additional help obtaining or using a ROR API client ID contact support@ror.org
  • + + {{#if this.model.registrationPaused}} + +

    Client ID registration is temporarily paused

    +

    We've paused new ROR API client ID registrations while we make updates to the service. No rate limits + are currently enforced based on the presence or absence of a client ID, and none will be introduced before + registration is restored, so API usage is not affected by this pause.

    +

    + If you have questions or an urgent request, please contact support@ror.org. + Thanks for your patience! +

    +
    + {{else}} + + {{/if}}
    -
    - {{#if this.model.registrationPaused}} - - Client ID registration is temporarily paused. -

    We've paused new ROR API client ID registrations while we make updates to the service. No rate limits - are currently enforced based on the presence or absence of a client ID, and none will be introduced before - registration is restored, so API usage is not affected by this pause. -

    -

    - If you have questions or an urgent request, please contact support@ror.org. - Thanks for your patience!

    -
    - {{/if}} - - -
    diff --git a/tests/acceptance/a11y/api-client-test.js b/tests/acceptance/a11y/api-client-test.js index 9f32b4cb..82790969 100644 --- a/tests/acceptance/a11y/api-client-test.js +++ b/tests/acceptance/a11y/api-client-test.js @@ -6,9 +6,17 @@ import a11yAudit from 'ember-a11y-testing/test-support/audit'; module('Acceptance | a11y | api-client-id', function (hooks) { setupApplicationTest(hooks); - test('the API client registration page has no axe violations', async function (assert) { + test('the API client registration page has no axe violations when paused', async function (assert) { + this.owner.lookup('service:config-service').set('CLIENT_ID_REGISTRATION_PAUSED', true); await visit('/api-client-id'); await a11yAudit(); - assert.ok(true, 'no axe violations on /api-client-id'); + assert.ok(true, 'no axe violations on /api-client-id when paused'); + }); + + test('the API client registration page has no axe violations when registration is open', async function (assert) { + this.owner.lookup('service:config-service').set('CLIENT_ID_REGISTRATION_PAUSED', false); + await visit('/api-client-id'); + await a11yAudit(); + assert.ok(true, 'no axe violations on /api-client-id when registration is open'); }); }); diff --git a/tests/acceptance/api-client-id-test.js b/tests/acceptance/api-client-id-test.js new file mode 100644 index 00000000..031e167f --- /dev/null +++ b/tests/acceptance/api-client-id-test.js @@ -0,0 +1,28 @@ +import { module, test } from 'qunit'; +import { setupApplicationTest } from 'ember-qunit'; +import { visit } from '@ember/test-helpers'; + +module('Acceptance | api-client-id', function (hooks) { + setupApplicationTest(hooks); + + test('when registration is paused, the banner is shown and the form is not rendered', async function (assert) { + this.owner.lookup('service:config-service').set('CLIENT_ID_REGISTRATION_PAUSED', true); + + await visit('/api-client-id'); + + assert.dom('.alert-warning').exists('paused banner is rendered'); + assert.dom('.alert-warning').includesText('Client ID registration is temporarily paused'); + assert.dom('.api-client-registration-form').doesNotExist('registration form is not rendered when paused'); + assert.dom('button[type="submit"]').doesNotExist('submit button is not rendered when paused'); + }); + + test('when registration is not paused, the form is rendered and the banner is not shown', async function (assert) { + this.owner.lookup('service:config-service').set('CLIENT_ID_REGISTRATION_PAUSED', false); + + await visit('/api-client-id'); + + assert.dom('.alert-warning').doesNotExist('paused banner is not rendered'); + assert.dom('.api-client-registration-form').exists('registration form is rendered'); + assert.dom('button[type="submit"]').exists('submit button is rendered'); + }); +}); diff --git a/tests/test-helper.js b/tests/test-helper.js index 0382a848..d33c1ee7 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -1,8 +1,12 @@ import Application from '../app'; import config from '../config/environment'; +import * as QUnit from 'qunit'; import { setApplication } from '@ember/test-helpers'; +import { setup } from 'qunit-dom'; import { start } from 'ember-qunit'; setApplication(Application.create(config.APP)); +setup(QUnit.assert); + start(); From 688c065655b936f53f09c54bcdeaecc9d76dc86d Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 22 May 2026 09:48:43 -0700 Subject: [PATCH 4/4] Fix pause banner email link contrast --- app/styles/app.scss | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/styles/app.scss b/app/styles/app.scss index 641322e3..5a6c529e 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -212,4 +212,18 @@ $desktop-width: 1024px; #clear-button { background-color:$dark-grey; color:$light-grey !important; +} + +.alert-warning { + color: $black; + + a { + color: $black; + text-decoration: underline; + + &:hover, + &:focus { + color: $black; + } + } } \ No newline at end of file