Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions src/app/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,12 @@ export const ORCID_URI_REGEXP =
// https://regex101.com/r/M1fqZi/1
export const URL_REGEXP =
/^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#%[\]@!\$&'\(\)\*\+\\,;=.>< ]+$/i
// ISSN pattern using same validation as the backend
//https://regex101.com/r/NYZTYS/1
export const ISSN_REGEXP = /\b\d{4}-?\d{3}[\dXx]\b/
export const ISSN_PORTAL_URL = 'https://portal.issn.org/resource/ISSN/'
// Escape the URL characters for Regex (handling slashes and dots)
const escapedUrl = ISSN_PORTAL_URL.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
export const ISSN_REGEXP = new RegExp(`^(?:${escapedUrl})?\\d{4}-?\\d{3}[\\dXx]$`);


/* PROTOCOL REQUIRED*/
// https://regex101.com/r/pSnDC7/1
export const URL_REGEXP_BACKEND =
Expand Down Expand Up @@ -516,3 +519,23 @@ function isValidIsbn13(isbn: string): boolean {
// The checksum must be perfectly divisible by 10.
return checksum % 10 === 0
}


function normaliseIssn(issn: string): string {
if (issn) {
// 1. Remove the portal URL
issn = issn.replace(new RegExp(ISSN_PORTAL_URL, 'g'), '')

// 2. Remove ALL non-alphanumeric characters (spaces, hyphens, dots, etc.)
issn = issn.replace(/[^a-zA-Z0-9]/g, '')

// 3. Force 'X' to uppercase
issn = issn.replace(/x/g, 'X')

// 4. Format as 0000-000X if valid length
if (issn.length === 8) {
return issn.substring(0, 4) + '-' + issn.substring(4, 8)
}
}
return ''
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { RecordCountriesService } from '../../../../../core/record-countries/rec
import { first, map, switchMap, tap } from 'rxjs/operators'
import {
ISSN_REGEXP,
ISSN_PORTAL_URL,
MAX_LENGTH_LESS_THAN_ONE_THOUSAND,
MAX_LENGTH_LESS_THAN_TWO_THOUSAND,
URL_REGEXP,
Expand Down Expand Up @@ -63,7 +64,6 @@ export class ModalAffiliationsComponent implements OnInit, OnDestroy {
issnLabel = $localize`:@@shared.link:Link`
endDateLabel = $localize`:@@shared.endDate:End date`

ISSN_PORTAL_URL = 'https://portal.issn.org/resource/ISSN/'

private _type: AffiliationType
dateLabel: string
Expand Down Expand Up @@ -394,13 +394,14 @@ export class ModalAffiliationsComponent implements OnInit, OnDestroy {
const normalizedIssn = this.normaliseIssn(
affiliationForm.get('issn')?.value?.trim()
)
const issnUrl = `${this.ISSN_PORTAL_URL}${normalizedIssn}`
const issnValue = affiliationForm.get('issn')?.value?.trim();
const issnUrl = `${ISSN_PORTAL_URL}${normalizedIssn}`
affiliationToSave.affiliationExternalIdentifiers = [
{
errors: [],
externalIdentifierId: {
errors: [],
value: affiliationForm.get('issn')?.value?.trim(),
value: issnValue && issnValue.startsWith(ISSN_PORTAL_URL)?issnUrl:normalizedIssn,
required: true,
},
externalIdentifierType: { value: 'issn' },
Expand Down Expand Up @@ -744,7 +745,7 @@ export class ModalAffiliationsComponent implements OnInit, OnDestroy {
normaliseIssn(issn: string) {
if (issn) {
// 1. Remove the portal URL
issn = issn.replace(new RegExp(this.ISSN_PORTAL_URL, 'g'), '')
issn = issn.replace(new RegExp(ISSN_PORTAL_URL, 'g'), '')

// 2. Remove ALL non-alphanumeric characters (spaces, hyphens, dots, etc.)
issn = issn.replace(/[^a-zA-Z0-9]/g, '')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
MAX_LENGTH_LESS_THAN_TWO_THOUSAND,
URL_REGEXP,
isValidISBN,
ISSN_REGEXP,
} from '../../../../constants'
import {
Contributor,
Expand Down Expand Up @@ -258,6 +259,17 @@ export class WorkFormComponent implements OnInit {
}
}

if (externalIdentifierType === 'issn') {
if (!ISSN_REGEXP.test(control.value)) {
control.markAsTouched()
return of({
validFormat: true,
resolved: false,
attemptedResolution: false,
})
}
}

return this._workService
.validateWorkIdTypes(externalIdentifierType, control.value)
.pipe(
Expand Down