diff --git a/akamai/exampleData/1_akamaiExport/userSchema.csv b/akamai/exampleData/1_akamaiExport/userSchema.csv new file mode 100644 index 0000000..fd5f9f4 --- /dev/null +++ b/akamai/exampleData/1_akamaiExport/userSchema.csv @@ -0,0 +1,66 @@ +Name,Type,Description,Length,Required,Unique,Case Sensitive,Searchable,Primary Key,Default Value,Write Once,Transformations,Legacy Validations +id,id,simple identifier for this entity,,false,globally,,true,false,,true,,0 +uuid,uuid,globally unique identifier for this entity,,false,globally,,true,false,,true,,0 +created,dateTime,when this entity was created,,false,,,true,false,,true,,0 +lastUpdated,dateTime,when this entity was last updated,,false,,,true,false,,false,,0 +accountDataRequestTime,dateTime,,,false,,,false,false,,false,,0 +accountDeleteRequestTime,dateTime,,,false,,,false,false,,false,,0 +birthday,date,End-User's birthday. Returned by the `birthdate` claim.,,false,,,true,false,,false,,0 +clients,plural,,,false,,,false,false,,false,,0 +clients.id,id,simple identifier for this sub-entity,,false,,,false,false,,false,,0 +clients.clientId,string,,,true,locally,true,true,true,,false,,0 +clients.firstLogin,dateTime,,,false,,,false,false,,false,,0 +clients.lastLogin,dateTime,,,false,,,false,false,,false,,0 +clients.name,string,,1000,false,,false,false,false,,false,,0 +consents,object,,,false,,,false,false,,false,,0 +consents.marketing,object,,,false,,,false,false,,false,,0 +consents.marketing.clientId,string,Client ID used to modify the consent.,32,false,,true,false,false,,false,,0 +consents.marketing.context,string,Context in which the consent was changed.,100,false,,true,false,false,,false,,0 +consents.marketing.granted,boolean,Whether or not the consent is granted.,,false,,,false,false,,false,,0 +consents.marketing.oidcClientId,string,OIDC Client ID used to modify the consent.,36,false,,true,false,false,,false,,0 +consents.marketing.type,string,"Type of consent, 'implicit' or 'explicit'.",8,false,,true,false,false,,false,,0 +consents.marketing.updated,dateTime,Date and time of the last change to the consent.,,false,,,false,false,,false,,0 +deactivateAccount,dateTime,Time when the account was deactivated.,,false,,,false,false,,false,,0 +display,json,Placeholder for public data. Referenced as 'public_display' in the flow.,,false,,,false,false,,false,,0 +displayName,string,"Shorthand name by which the End-User wishes to be referred to at the RP, such as janedoe or j.doe. Returned by the `preferred_username` claim.",1000,false,,false,true,false,,false,,0 +email,string,End-User's preferred e-mail address. Returned by the `email` claim.,256,false,globally,false,true,false,,false,,0 +emailVerified,dateTime,Time when the email address was verified. Returned as boolean by the `email_verified` claim.,,false,,,false,false,,false,,0 +externalId,string,,1000,false,,false,false,false,,false,,0 +familyName,string,Surname(s) or last name(s) of the End-User. Returned by the `family_name` claim.,1000,false,,false,true,false,,false,,0 +fullName,string,"End-User's full name in displayable form including all name parts, possibly including titles and suffixes, ordered according to the End-User's locale and preferences. Returned by the `name` claim.",1000,false,,false,true,false,,false,,0 +gender,string,End-User's gender. Returned by the `gender` claim.,100,false,,false,false,false,,false,,0 +givenName,string,Given name(s) or first name(s) of the End-User. Returned by the `given_name` claim.,1000,false,,false,true,false,,false,,0 +lastLogin,dateTime,Time of the last authentication.,,false,,,false,false,,false,,0 +legalAcceptances,plural,,,false,,,false,false,,false,,0 +legalAcceptances.id,id,simple identifier for this sub-entity,,false,,,false,false,,false,,0 +legalAcceptances.clientId,string,,32,false,,true,false,false,,false,,0 +legalAcceptances.dateAccepted,dateTime,,,false,,,false,false,,false,,0 +legalAcceptances.legalAcceptanceId,string,,1000,true,locally,false,true,true,,false,,0 +middleName,string,Middle name(s) of the End-User. Returned by the `middle_name` claim.,1000,false,,false,false,false,,false,,0 +mobileNumber,string,,256,false,globally,false,true,false,,false,,0 +mobileNumberVerified,dateTime,,,false,,,false,false,,false,,0 +password,password-bcrypt,End-User's password.,,false,,,false,false,,false,,0 +photos,plural,Primary user profile photos.,,false,,,false,false,,false,,0 +photos.id,id,simple identifier for this sub-entity,,false,,,false,false,,false,,0 +photos.type,string,,,false,,true,false,false,,false,,0 +photos.value,string,,,false,,true,false,false,,false,,0 +primaryAddress,object,End-User's preferred postal address. Returned by the `address` claim.,,false,,,false,false,,false,,0 +primaryAddress.address1,string,,1000,false,,false,false,false,,false,,0 +primaryAddress.address2,string,,1000,false,,false,false,false,,false,,0 +primaryAddress.city,string,,1000,false,,false,false,false,,false,,0 +primaryAddress.company,string,,1000,false,,false,false,false,,false,,0 +primaryAddress.country,string,,1000,false,,false,false,false,,false,,0 +primaryAddress.phone,string,,100,false,,false,true,false,,false,,0 +primaryAddress.stateAbbreviation,string,,100,false,,false,false,false,,false,,0 +primaryAddress.zip,string,,100,false,,false,false,false,,false,,0 +primaryAddress.zipPlus4,string,,100,false,,false,false,false,,false,,0 +profiles,plural,,,false,,,false,false,,false,,0 +profiles.id,id,simple identifier for this sub-entity,,false,,,false,false,,false,,0 +profiles.domain,string,,1000,false,,false,false,false,,false,,0 +profiles.identifier,string,Profile provider unique identifier,1000,true,globally,false,true,false,,false,,0 +profiles.photo,string,URL of a photo of this contact.,,false,,true,false,false,,false,,0 +profiles.providerSpecifier,string,Internal text field for identifying the provider in a unique and normalized manner.,,false,,true,false,false,,false,,0 +roles,plural,"A list of roles for the User that collectively represent who the User is, e.g., 'Student', 'Faculty'.",,false,,,false,false,,false,,0 +roles.id,id,simple identifier for this sub-entity,,false,,,false,false,,false,,0 +roles.display,string,"A human-readable name, primarily used for display purposes.",1000,false,,true,false,false,,false,,0 +roles.value,string,The value of a role.,256,true,locally,false,true,true,,false,,0 \ No newline at end of file diff --git a/akamai/exampleData/1_akamaiExport/userSchema.js b/akamai/exampleData/1_akamaiExport/userSchema.js new file mode 100644 index 0000000..bf1bcf5 --- /dev/null +++ b/akamai/exampleData/1_akamaiExport/userSchema.js @@ -0,0 +1,957 @@ +[ + { + name: "id", + type: "id", + description: "simple identifier for this entity", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "uuid", + type: "uuid", + description: "globally unique identifier for this entity", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "created", + type: "dateTime", + description: "when this entity was created", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "lastUpdated", + type: "dateTime", + description: "when this entity was last updated", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "accountDataRequestTime", + type: "dateTime", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "accountDeleteRequestTime", + type: "dateTime", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "birthday", + type: "date", + description: "End-User's birthday. Returned by the `birthdate` claim.", + "locally-unique": false, + query: true, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "clients", + type: "plural", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "clients.id", + type: "id", + description: "simple identifier for this sub-entity", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "clients.clientId", + type: "string", + "case-sensitive": true, + "locally-unique": true, + query: false, + required: true, + "primary-key": true, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "clients.firstLogin", + type: "dateTime", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "clients.lastLogin", + type: "dateTime", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "clients.name", + type: "string", + "case-sensitive": false, + length: 1000, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "consents", + type: "object", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "consents.marketing", + type: "object", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "consents.marketing.clientId", + type: "string", + "case-sensitive": true, + description: "Client ID used to modify the consent.", + length: 32, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "consents.marketing.context", + type: "string", + "case-sensitive": true, + description: "Context in which the consent was changed.", + length: 100, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "consents.marketing.granted", + type: "boolean", + description: "Whether or not the consent is granted.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "consents.marketing.oidcClientId", + type: "string", + "case-sensitive": true, + description: "OIDC Client ID used to modify the consent.", + length: 36, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "consents.marketing.type", + type: "string", + "case-sensitive": true, + description: "Type of consent, 'implicit' or 'explicit'.", + length: 8, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "consents.marketing.updated", + type: "dateTime", + description: "Date and time of the last change to the consent.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "deactivateAccount", + type: "dateTime", + description: "Time when the account was deactivated.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "display", + type: "json", + description: + "Placeholder for public data. Referenced as 'public_display' in the flow.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "displayName", + type: "string", + "case-sensitive": false, + description: + "Shorthand name by which the End-User wishes to be referred to at the RP, such as janedoe or j.doe. Returned by the `preferred_username` claim.", + length: 1000, + "locally-unique": false, + query: true, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "email", + type: "string", + "case-sensitive": false, + description: + "End-User's preferred e-mail address. Returned by the `email` claim.", + length: 256, + "locally-unique": false, + query: true, + required: false, + "primary-key": false, + "reverse-query": true, + unique: true, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "emailVerified", + type: "dateTime", + description: + "Time when the email address was verified. Returned as boolean by the `email_verified` claim.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "externalId", + type: "string", + "case-sensitive": false, + length: 1000, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "familyName", + type: "string", + "case-sensitive": false, + description: + "Surname(s) or last name(s) of the End-User. Returned by the `family_name` claim.", + length: 1000, + "locally-unique": false, + query: true, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "fullName", + type: "string", + "case-sensitive": false, + description: + "End-User's full name in displayable form including all name parts, possibly including titles and suffixes, ordered according to the End-User's locale and preferences. Returned by the `name` claim.", + length: 1000, + "locally-unique": false, + query: true, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "gender", + type: "string", + "case-sensitive": false, + description: "End-User's gender. Returned by the `gender` claim.", + length: 100, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "givenName", + type: "string", + "case-sensitive": false, + description: + "Given name(s) or first name(s) of the End-User. Returned by the `given_name` claim.", + length: 1000, + "locally-unique": false, + query: true, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "lastLogin", + type: "dateTime", + description: "Time of the last authentication.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "legalAcceptances", + type: "plural", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "legalAcceptances.id", + type: "id", + description: "simple identifier for this sub-entity", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "legalAcceptances.clientId", + type: "string", + "case-sensitive": true, + length: 32, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "legalAcceptances.dateAccepted", + type: "dateTime", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "legalAcceptances.legalAcceptanceId", + type: "string", + "case-sensitive": false, + length: 1000, + "locally-unique": true, + query: false, + required: true, + "primary-key": true, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "middleName", + type: "string", + "case-sensitive": false, + description: + "Middle name(s) of the End-User. Returned by the `middle_name` claim.", + length: 1000, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "mobileNumber", + type: "string", + "case-sensitive": false, + length: 256, + "locally-unique": false, + query: true, + required: false, + "primary-key": false, + "reverse-query": false, + unique: true, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "mobileNumberVerified", + type: "dateTime", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "password", + type: "password-bcrypt", + description: "End-User's password.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "photos", + type: "plural", + description: "Primary user profile photos.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "photos.id", + type: "id", + description: "simple identifier for this sub-entity", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "photos.type", + type: "string", + "case-sensitive": true, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "photos.value", + type: "string", + "case-sensitive": true, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "primaryAddress", + type: "object", + description: + "End-User's preferred postal address. Returned by the `address` claim.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "primaryAddress.address1", + type: "string", + "case-sensitive": false, + length: 1000, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "primaryAddress.address2", + type: "string", + "case-sensitive": false, + length: 1000, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "primaryAddress.city", + type: "string", + "case-sensitive": false, + length: 1000, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "primaryAddress.company", + type: "string", + "case-sensitive": false, + length: 1000, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "primaryAddress.country", + type: "string", + "case-sensitive": false, + length: 1000, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "primaryAddress.phone", + type: "string", + "case-sensitive": false, + length: 100, + "locally-unique": false, + query: true, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "primaryAddress.stateAbbreviation", + type: "string", + "case-sensitive": false, + length: 100, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "primaryAddress.zip", + type: "string", + "case-sensitive": false, + length: 100, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "primaryAddress.zipPlus4", + type: "string", + "case-sensitive": false, + length: 100, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "profiles", + type: "plural", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "profiles.id", + type: "id", + description: "simple identifier for this sub-entity", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "profiles.domain", + type: "string", + "case-sensitive": false, + length: 1000, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "profiles.identifier", + type: "string", + "case-sensitive": false, + description: "Profile provider unique identifier", + length: 1000, + "locally-unique": false, + query: false, + required: true, + "primary-key": false, + "reverse-query": false, + unique: true, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "profiles.photo", + type: "string", + "case-sensitive": true, + description: "URL of a photo of this contact.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "profiles.providerSpecifier", + type: "string", + "case-sensitive": true, + description: + "Internal text field for identifying the provider in a unique and normalized manner.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "roles", + type: "plural", + description: + "A list of roles for the User that collectively represent who the User is, e.g., 'Student', 'Faculty'.", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "roles.id", + type: "id", + description: "simple identifier for this sub-entity", + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "roles.display", + type: "string", + "case-sensitive": true, + description: "A human-readable name, primarily used for display purposes.", + length: 1000, + "locally-unique": false, + query: false, + required: false, + "primary-key": false, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, + { + name: "roles.value", + type: "string", + "case-sensitive": false, + description: "The value of a role.", + length: 256, + "locally-unique": true, + query: false, + required: true, + "primary-key": true, + "reverse-query": false, + unique: false, + "to-upper": false, + "to-lower": false, + "ignore-update": false, + }, +]; diff --git a/akamai/exampleData/1_akamaiExport/users.json b/akamai/exampleData/1_akamaiExport/users.json new file mode 100644 index 0000000..dbd55a6 --- /dev/null +++ b/akamai/exampleData/1_akamaiExport/users.json @@ -0,0 +1,156 @@ +{ + "result_count": 2, + "results": [ + { + "accountDataRequestTime": null, + "accountDeleteRequestTime": null, + "birthday": "1980-05-01", + "clients": [ + { + "clientId": "9a55jnetfgjf8mzdmjbugdmyr55tc2j9", + "firstLogin": "2025-05-08 09:35:22 +0000", + "id": 130, + "lastLogin": "2025-05-08 09:35:22 +0000", + "name": null + } + ], + "consents": { + "marketing": { + "clientId": null, + "context": null, + "granted": null, + "oidcClientId": null, + "type": null, + "updated": null + } + }, + "created": "2025-05-08 09:35:22.556125 +0000", + "deactivateAccount": null, + "display": null, + "displayName": "Jane Smith", + "email": "janesmith@example.com", + "emailVerified": "2025-05-08 10:06:56 +0000", + "externalId": null, + "familyName": "Smith", + "fullName": "Jane Smith", + "gender": "Female", + "givenName": "Jane", + "id": 129, + "lastLogin": "2025-05-08 09:35:22 +0000", + "lastUpdated": "2025-05-08 10:06:58.321921 +0000", + "legalAcceptances": [ + { + "clientId": "9a55jnetfgjf8mzdmjbugdmyr55tc2j9", + "dateAccepted": "2025-05-08 09:35:22 +0000", + "id": 131, + "legalAcceptanceId": "termsOfService-v1" + }, + { + "clientId": "9a55jnetfgjf8mzdmjbugdmyr55tc2j9", + "dateAccepted": "2025-05-08 09:35:22 +0000", + "id": 132, + "legalAcceptanceId": "privacyPolicy-v1" + } + ], + "middleName": null, + "mobileNumber": "+12 345 6789", + "mobileNumberVerified": "2025-05-06 10:06:56 +0000", + "password": { + "created": "2025-05-08 09:35:22.555420794 +0000", + "type": "password-bcrypt", + "value": "$2b$10$fGr0/0QnnDkv9VG0BtyaiOj9Fb5rNQTXkrCcidzQqR061kc6e5VBu" + }, + "photos": [], + "primaryAddress": { + "address1": "1 Evergreen way", + "address2": null, + "city": "Sunnydale", + "company": "First Bank", + "country": "NZ", + "phone": null, + "stateAbbreviation": null, + "zip": "9876", + "zipPlus4": null + }, + "profiles": [], + "roles": [{ "display": "manager", "id": 257, "value": "manager" }], + "uuid": "36cdc8af-909f-48d3-909d-313a9fdfe6c1" + }, + { + "accountDataRequestTime": null, + "accountDeleteRequestTime": null, + "birthday": "1990-05-20", + "clients": [ + { + "clientId": "9a55jnetfgjf8mzdmjbugdmyr55tc2j9", + "firstLogin": "2025-05-08 10:08:30 +0000", + "id": 386, + "lastLogin": "2025-05-08 10:08:30 +0000", + "name": null + } + ], + "consents": { + "marketing": { + "clientId": null, + "context": null, + "granted": null, + "oidcClientId": null, + "type": null, + "updated": null + } + }, + "created": "2025-05-08 10:08:30.544839 +0000", + "deactivateAccount": null, + "display": null, + "displayName": "John Doe", + "email": "johndoe@example.com", + "emailVerified": null, + "externalId": null, + "familyName": "Doe", + "fullName": "Johnathan Montgomery Doe", + "gender": "Male", + "givenName": "John", + "id": 385, + "lastLogin": "2025-05-08 10:08:30 +0000", + "lastUpdated": "2025-05-08 10:19:23.129255 +0000", + "legalAcceptances": [ + { + "clientId": "9a55jnetfgjf8mzdmjbugdmyr55tc2j9", + "dateAccepted": "2025-05-08 10:08:30 +0000", + "id": 387, + "legalAcceptanceId": "termsOfService-v1" + }, + { + "clientId": "9a55jnetfgjf8mzdmjbugdmyr55tc2j9", + "dateAccepted": "2025-05-08 10:08:30 +0000", + "id": 388, + "legalAcceptanceId": "privacyPolicy-v1" + } + ], + "middleName": "Montgomery", + "mobileNumber": null, + "mobileNumberVerified": null, + "password": { + "created": "2025-05-08 10:08:30.544094645 +0000", + "type": "password-bcrypt", + "value": "$2b$10$E.FMZSb32qkZJJqnZT/RUuLS7DwepOS7sgmM/8adQ8BlzYrwX/T1." + }, + "photos": [], + "primaryAddress": { + "address1": "2", + "address2": "North Way", + "city": "Barcelona", + "company": null, + "country": "Zimbabwe", + "phone": "987 6542", + "stateAbbreviation": "xuio", + "zip": "1235", + "zipPlus4": null + }, + "profiles": [], + "roles": [{ "display": "Customer", "id": 513, "value": "cust" }], + "uuid": "1e3a957f-be82-4dd1-b46a-a96a45233eef" + } + ], + "stat": "ok" +} diff --git a/akamai/exampleData/2_faImport/faUsers.json b/akamai/exampleData/2_faImport/faUsers.json new file mode 100644 index 0000000..5b92cd6 --- /dev/null +++ b/akamai/exampleData/2_faImport/faUsers.json @@ -0,0 +1,112 @@ +[ + { + "email": "janesmith@example.com", + "encryptionScheme": "bcrypt", + "id": "36cdc8af-909f-48d3-909d-313a9fdfe6c1", + "lastLoginInstant": 1746696922000, + "factor": "10", + "password": "j9Fb5rNQTXkrCcidzQqR061kc6e5VBu", + "passwordChangeRequired": false, + "salt": "fGr0/0QnnDkv9VG0BtyaiO", + "uniqueUsername": "janesmith@example.com", + "username": "Jane Smith", + "verified": true, + "active": true, + "birthDate": "1980-05-01", + "firstName": "Jane", + "lastName": "Smith", + "middleName": null, + "mobilePhone": "+12 345 6789", + "registrations": [ + { + "applicationId": "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e", + "roles": ["manager"] + } + ], + "tenantId": "d7d09513-a3f5-401c-9685-34ab6c552453", + "data": { + "akamaiId": 129, + "createdAt": "2025-05-08 09:35:22.556125 +0000", + "lastUpdatedAt": "2025-05-08 10:06:58.321921 +0000", + "accountDataRequestTime": null, + "accountDeleteRequestTime": null, + "birthday": "1980-05-01", + "accountDeactivatedAt": null, + "display": null, + "emailVerifiedAt": "2025-05-08 10:06:56 +0000", + "externalId": null, + "fullName": "Jane Smith", + "gender": "Female", + "mobileNumberVerified": "2025-05-06 10:06:56 +0000", + "legalAcceptances": [ + { + "id": 131, + "clientId": "9a55jnetfgjf8mzdmjbugdmyr55tc2j9", + "dateAccepted": "2025-05-08 09:35:22 +0000", + "legalAcceptanceID": "termsOfService-v1" + }, + { + "id": 132, + "clientId": "9a55jnetfgjf8mzdmjbugdmyr55tc2j9", + "dateAccepted": "2025-05-08 09:35:22 +0000", + "legalAcceptanceID": "privacyPolicy-v1" + } + ] + } + }, + { + "email": "johndoe@example.com", + "encryptionScheme": "bcrypt", + "id": "1e3a957f-be82-4dd1-b46a-a96a45233eef", + "lastLoginInstant": 1746698910000, + "factor": "10", + "password": "LS7DwepOS7sgmM/8adQ8BlzYrwX/T1.", + "passwordChangeRequired": false, + "salt": "E.FMZSb32qkZJJqnZT/RUu", + "uniqueUsername": "johndoe@example.com", + "username": "John Doe", + "verified": false, + "active": true, + "birthDate": "1990-05-20", + "firstName": "John", + "lastName": "Doe", + "middleName": "Montgomery", + "mobilePhone": null, + "registrations": [ + { + "applicationId": "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e", + "roles": ["cust"] + } + ], + "tenantId": "d7d09513-a3f5-401c-9685-34ab6c552453", + "data": { + "akamaiId": 385, + "createdAt": "2025-05-08 10:08:30.544839 +0000", + "lastUpdatedAt": "2025-05-08 10:19:23.129255 +0000", + "accountDataRequestTime": null, + "accountDeleteRequestTime": null, + "birthday": "1990-05-20", + "accountDeactivatedAt": null, + "display": null, + "emailVerifiedAt": null, + "externalId": null, + "fullName": "Johnathan Montgomery Doe", + "gender": "Male", + "mobileNumberVerified": null, + "legalAcceptances": [ + { + "id": 387, + "clientId": "9a55jnetfgjf8mzdmjbugdmyr55tc2j9", + "dateAccepted": "2025-05-08 10:08:30 +0000", + "legalAcceptanceID": "termsOfService-v1" + }, + { + "id": 388, + "clientId": "9a55jnetfgjf8mzdmjbugdmyr55tc2j9", + "dateAccepted": "2025-05-08 10:08:30 +0000", + "legalAcceptanceID": "privacyPolicy-v1" + } + ] + } + } +] diff --git a/akamai/src/.gitignore b/akamai/src/.gitignore new file mode 100644 index 0000000..294afa3 --- /dev/null +++ b/akamai/src/.gitignore @@ -0,0 +1,3 @@ +faUsers.json +users.json +userSchema.csv diff --git a/akamai/src/1_addRoles.mjs b/akamai/src/1_addRoles.mjs new file mode 100644 index 0000000..5dbf2af --- /dev/null +++ b/akamai/src/1_addRoles.mjs @@ -0,0 +1,43 @@ +import { v4 as uuidv4 } from 'uuid'; +import fs from 'fs'; + +const inputFilename = 'users.json'; +const applicationId = 'e9fdb985-9173-4e01-9d73-ac2d60d1dc8e'; +const apiKey = '33052c8a-c283-4e96-9d2a-eb1215c69f8f-not-for-prod'; +const fusionauthUrl = 'http://fa:9011'; + +await createRoles(); + +async function createRoles() { + const json = JSON.parse(fs.readFileSync(inputFilename, 'utf8')); + for (const user of json.results) { + if (user.roles && user.roles.length > 0) { + for (const role of user.roles) { + const roleId = uuidv4(); + try { + const response = await fetch( + `${fusionauthUrl}/api/application/${applicationId}/role/${roleId}`, + { + method: 'POST', + headers: { + 'Authorization': apiKey, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + "role": { + "description": role.display, + "name": role.value, + "isDefault": false, + "isSuperRole": false + } + }) + } + ); + if (response.ok) console.log(`Role with ID ${roleId} for ${role.value} created successfully.`); + else console.error(`Failed to create role with ID ${roleId}. Status: ${response.status}`); + } + catch (error) { console.error(`Error creating role with ID ${roleId}:`, error); } + } + } + } +} diff --git a/akamai/src/2_convertUserToFaUser.mjs b/akamai/src/2_convertUserToFaUser.mjs new file mode 100644 index 0000000..eabe4d2 --- /dev/null +++ b/akamai/src/2_convertUserToFaUser.mjs @@ -0,0 +1,156 @@ +import { promises as fsp } from 'fs'; +import * as fs from 'fs'; +import { v4 as uuidv4 } from 'uuid'; +import parser from 'stream-json'; +import StreamArray from 'stream-json/streamers/StreamArray.js'; +import Chain from 'stream-chain'; +import Pick from 'stream-json/filters/Pick.js'; + +const inputFilename = 'users.json'; +const outputFilename = 'faUsers.json'; +const applicationId = 'e9fdb985-9173-4e01-9d73-ac2d60d1dc8e'; +const apiKey = '33052c8a-c283-4e96-9d2a-eb1215c69f8f-not-for-prod'; +const fusionauthUrl = 'http://fa:9011'; + +await processUsers(); + +async function processUsers() { + try { + await fsp.writeFile(outputFilename, '[\n', 'utf8'); + const inputUsers = new Chain([fs.createReadStream(inputFilename ), Pick.withParser({filter: 'results'}), new StreamArray()]); + let isFirstLine = true; + for await (const { value: user } of inputUsers) { + if (!isFirstLine) await fsp.appendFile(outputFilename, ',\n', 'utf8'); + isFirstLine = false; + await fsp.appendFile(outputFilename, JSON.stringify(getFaUserFromUser(user)), 'utf8'); + } + await fsp.appendFile(outputFilename, '\n]', 'utf8'); + } catch (e) { + console.dir(e); + } +} + +// Fields are detailed here: https://fusionauth.io/docs/apis/users#request-6 +function getFaUserFromUser(user) { + const faUser = {}; + + // SecureIdentity fields ------ + // faUser.breachedPasswordLastCheckedInstant = number; + // faUser.breachedPasswordStatus = BreachedPasswordStatus; + // faUser.connectorId = UUID; + faUser.email = user.email; + faUser.encryptionScheme = 'bcrypt'; + faUser.id = user.uuid + if (user.lastLogin) + faUser.lastLoginInstant = new Date(user.lastLogin).getTime(); + faUser.factor = user.password?.value.split('$')[2]; + faUser.password = user.password?.value.split('$')[3].substring(22); + faUser.passwordChangeRequired = false; + //faUser.passwordChangeReason = "Administrative"; + // faUser.passwordLastUpdateInstant = number; + faUser.salt = user.password?.value.split('$')[3].substring(0, 22);; + faUser.uniqueUsername = user.email; + faUser.username = user.displayName; + // faUser.usernameStatus = ContentStatus; + faUser.verified = (user.emailVerified != null); + // faUser.verifiedInstant = number; + + // User fields ------ + faUser.active = !user.deactivateAccount; + faUser.birthDate = user.birthday; + // faUser.cleanSpeakId = UUID; + // faUser.expiry = number; + faUser.firstName = user.givenName; + faUser.imageUrl = user.profilePictureUrl; + // faUser.insertInstant = number; + faUser.lastName = user.familyName; + // faUser.lastUpdateInstant = number; + // faUser.memberships = Array; + faUser.middleName = user.middleName; + faUser.mobilePhone = user.mobileNumber; + // faUser.parentEmail = string; + // faUser.preferredLanguages = Array; + if (user.roles?.length > 0) { + faUser.registrations = [{ + 'applicationId': applicationId, + 'roles': [] + }]; + for (let role of user.roles) + faUser.registrations[0].roles.push(role.value); + } + faUser.tenantId = 'd7d09513-a3f5-401c-9685-34ab6c552453'; + // faUser.timezone = string; + // faUser.twoFactor = UserTwoFactorConfiguration; + + faUser.data = {}; + faUser.data.akamaiId = user.id; + faUser.data.createdAt = user.created; + faUser.data.lastUpdatedAt = user.lastUpdated; + faUser.data.accountDataRequestTime = user.accountDataRequestTime; + faUser.data.accountDeleteRequestTime = user.accountDeleteRequestTime; + faUser.data.birthday = user.birthday; + faUser.data.accountDeactivatedAt = user.deactivateAccount; + faUser.data.display = user.display; + faUser.data.emailVerifiedAt = user.emailVerified; + faUser.data.externalId = user.externalId; + faUser.data.fullName = user.fullName; + faUser.data.gender = user.gender; + faUser.data.mobileNumberVerified = user.mobileNumberVerified; + + if (user.consents?.length > 0) { + faUser.data.consents = []; + for (let item of user.consents){ + faUser.data.consents.push({ + 'clientId': item.marketing.clientId, + 'context' : item.marketing.context, + 'granted' : item.marketing.granted, + 'oidcClientId' : item.marketing.oidcClientId, + 'type' : item.marketing.type, + }); + } + } + + if (user.legalAcceptances?.length > 0) { + faUser.data.legalAcceptances = []; + for (let item of user.legalAcceptances){ + faUser.data.legalAcceptances.push({ + 'id': item.id, + 'clientId' : item.clientId, + 'dateAccepted' : item.dateAccepted, + 'legalAcceptanceID' : item.legalAcceptanceId + }); + } + } + + if (user.primaryAddress?.length > 0) { + faUser.data.addresses = []; + for (let item of user.primaryAddress){ + faUser.data.addresses.push({ + 'address1': item.address1, + 'address2' : item.address2, + 'city' : item.city, + 'company' : item.company, + 'country' : item.country, + 'phone' : item.phone, + 'stateAbbreviation' : item.stateAbbreviation, + 'zip' : item.zip, + 'zipPlus4' : item.zipPlus4 + }); + } + } + + if (user.profiles?.length > 0) { + faUser.data.profiles = []; + for (let item of user.profiles) { + faUser.data.profiles.push({ + 'id': item.id, + 'domain': item.domain, + 'identifier': item.identifier, + 'photo': item.photo, + 'providerSpecifier': item.providerSpecifier + }); + } + } + + return faUser; +} diff --git a/akamai/src/3_import.mjs b/akamai/src/3_import.mjs new file mode 100644 index 0000000..4fb721f --- /dev/null +++ b/akamai/src/3_import.mjs @@ -0,0 +1,32 @@ +import parser from 'stream-json'; +import StreamArray from 'stream-json/streamers/StreamArray.js'; +import Chain from 'stream-chain'; +import * as fs from "fs"; + +const apiKey = '33052c8a-c283-4e96-9d2a-eb1215c69f8f-not-for-prod'; +const fusionauthUrl = 'http://fa:9011'; +const filename = 'faUsers.json'; + +processUsers(); + +async function processUsers() { + const users = new Chain([fs.createReadStream(filename), parser(), new StreamArray(),]); + for await (const { value: user } of users) + await importUser(user); +} + +async function importUser(user) { + try { + const response = await fetch(`${fusionauthUrl}/api/user/import`, { + method: 'POST', + headers: { 'Authorization': apiKey, 'Content-Type': 'application/json'}, + body: JSON.stringify({ users: [user], validateDbConstraints: true }) + }); + if (response.ok) console.log(`User ${user.email} imported successfully`); + else { + const errorData = await response.json(); + console.error(`Error importing user ${user.email}`, errorData); + } + } + catch (error) { console.error('Error:', error); } +} diff --git a/akamai/src/4_connectorService.mjs b/akamai/src/4_connectorService.mjs new file mode 100644 index 0000000..cc96a83 --- /dev/null +++ b/akamai/src/4_connectorService.mjs @@ -0,0 +1,181 @@ +// Documentation at https://fusionauth.io/docs/lifecycle/migrate-users/connectors/generic-connector + +import express from 'express'; + +const applicationId = 'e9fdb985-9173-4e01-9d73-ac2d60d1dc8e'; + +const app = express(); +app.use(express.json()); +app.post('/', async (request, response) => { + console.log(`Request received for ${request.body.loginId}`); + const email = request.body.loginId; + const password = request.body.password; + const { isValid, user } = await isLoginValid(email, request.body.password); + if (!isValid) + return response.status(404).end(); + console.log('User login verified. Returning details below to FusionAuth'); + console.dir({ 'user': { ...user, 'password': password } }); + return response.status(200).json({ 'user': { ...user, 'password': password } }); +}); +app.listen(80, '0.0.0.0'); +console.log('Service running'); + +async function isLoginValid(email, password) { + try { + const response = await fetch('https://test-env.us-dev.janraincapture.com/oauth/auth_native_traditional', { + method: 'POST', + headers: { 'accept': 'application/json', 'content-type': 'application/x-www-form-urlencoded'}, + body: new URLSearchParams({ + client_id: '9a55jnetfgjf8mzdmjbugdmyr55tc2j9', + flow_version: '20250502165159394037', + flow: 'standard', + locale: 'en-US', + form: 'signInForm', + redirect_uri: 'http://localhost', + currentPassword: password, + signInEmailAddress: email + }).toString() + }); + const data = await response.json(); + console.log('Data received from Akamai:'); + console.dir(data); + if (response.status == 200 && data.stat == 'ok') + return { 'isValid': true, 'user': getFaUserFromUser(data.capture_user)}; + else + return { 'isValid': false, 'user': null }; + } + catch (e) { return false; } +} + +// Fields are detailed here: https://fusionauth.io/docs/apis/users#request-6 +function getFaUserFromUser(user) { + try { + const faUser = {}; + + // SecureIdentity fields ------ + // faUser.breachedPasswordLastCheckedInstant = number; + // faUser.breachedPasswordStatus = BreachedPasswordStatus; + // faUser.connectorId = UUID; + faUser.email = user.email; + faUser.encryptionScheme = 'bcrypt'; + faUser.id = user.uuid + if (user.lastLogin) + faUser.lastLoginInstant = new Date(user.lastLogin).getTime(); + // faUser.factor = user.password?.value.split('$')[2]; + // faUser.password = user.password?.value.split('$')[3].substring(22); + faUser.passwordChangeRequired = false; + //faUser.passwordChangeReason = "Administrative"; + // faUser.passwordLastUpdateInstant = number; + // faUser.salt = user.password?.value.split('$')[3].substring(0, 22);; + faUser.uniqueUsername = user.email; + faUser.username = user.displayName; + // faUser.usernameStatus = ContentStatus; + faUser.verified = (user.emailVerified != null); + // faUser.verifiedInstant = number; + + // User fields ------ + faUser.active = !user.deactivateAccount; + faUser.birthDate = user.birthday; + // faUser.cleanSpeakId = UUID; + // faUser.expiry = number; + faUser.firstName = user.givenName; + faUser.imageUrl = user.profilePictureUrl; + // faUser.insertInstant = number; + faUser.lastName = user.familyName; + // faUser.lastUpdateInstant = number; + // faUser.memberships = Array; + faUser.middleName = user.middleName; + faUser.mobilePhone = user.mobileNumber; + // faUser.parentEmail = string; + // faUser.preferredLanguages = Array; + if (user.roles?.length > 0) { + faUser.registrations = [{ + 'applicationId': applicationId, + 'roles': [] + }]; + for (let role of user.roles) + faUser.registrations[0].roles.push(role.value); + } + faUser.tenantId = 'd7d09513-a3f5-401c-9685-34ab6c552453'; + // faUser.timezone = string; + // faUser.twoFactor = UserTwoFactorConfiguration; + + faUser.data = {}; + faUser.data.akamaiId = user.id; + faUser.data.createdAt = user.created; + faUser.data.lastUpdatedAt = user.lastUpdated; + faUser.data.accountDataRequestTime = user.accountDataRequestTime; + faUser.data.accountDeleteRequestTime = user.accountDeleteRequestTime; + faUser.data.birthday = user.birthday; + faUser.data.accountDeactivatedAt = user.deactivateAccount; + faUser.data.display = user.display; + faUser.data.emailVerifiedAt = user.emailVerified; + faUser.data.externalId = user.externalId; + faUser.data.fullName = user.fullName; + faUser.data.gender = user.gender; + faUser.data.mobileNumberVerified = user.mobileNumberVerified; + + if (user.consents?.length > 0) { + faUser.data.consents = []; + for (let item of user.consents) { + faUser.data.consents.push({ + 'clientId': item.marketing.clientId, + 'context': item.marketing.context, + 'granted': item.marketing.granted, + 'oidcClientId': item.marketing.oidcClientId, + 'type': item.marketing.type, + }); + } + } + + if (user.legalAcceptances?.length > 0) { + faUser.data.legalAcceptances = []; + for (let item of user.legalAcceptances) { + faUser.data.legalAcceptances.push({ + 'id': item.id, + 'clientId': item.clientId, + 'dateAccepted': item.dateAccepted, + 'legalAcceptanceID': item.legalAcceptanceId + }); + } + } + + //photos not imported + + if (user.primaryAddress?.length > 0) { + faUser.data.addresses = []; + for (let item of user.primaryAddress) { + faUser.data.addresses.push({ + 'address1': item.address1, + 'address2': item.address2, + 'city': item.city, + 'company': item.company, + 'country': item.country, + 'phone': item.phone, + 'stateAbbreviation': item.stateAbbreviation, + 'zip': item.zip, + 'zipPlus4': item.zipPlus4 + }); + } + } + + if (user.profiles?.length > 0) { + faUser.data.profiles = []; + for (let item of user.profiles) { + faUser.data.profiles.push({ + 'id': item.id, + 'domain': item.domain, + 'identifier': item.identifier, + 'photo': item.photo, + 'providerSpecifier': item.providerSpecifier + }); + } + } + + return faUser; + } + catch (e) { + console.log('Error converting Akamai user to FA user:'); + console.dir(e); + } +} diff --git a/akamai/src/package.json b/akamai/src/package.json new file mode 100644 index 0000000..fd8d819 --- /dev/null +++ b/akamai/src/package.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "express": "^5.1.0", + "stream-json": "^1.9.1", + "util": "^0.12.5", + "uuid": "^9.0.1" + } +}