diff --git a/commons/src/main/java/org/georchestra/security/api/OrganizationsApi.java b/commons/src/main/java/org/georchestra/security/api/OrganizationsApi.java index d72481b4b9..a3db739f21 100644 --- a/commons/src/main/java/org/georchestra/security/api/OrganizationsApi.java +++ b/commons/src/main/java/org/georchestra/security/api/OrganizationsApi.java @@ -29,6 +29,8 @@ public interface OrganizationsApi { Optional findById(String id); + Optional findByOrgUniqueId(String id); + Optional findByShortName(String shortName); Optional getLogo(String id); diff --git a/commons/src/main/java/org/georchestra/security/model/Organization.java b/commons/src/main/java/org/georchestra/security/model/Organization.java index fa2e6df7dc..ffd9e481fd 100644 --- a/commons/src/main/java/org/georchestra/security/model/Organization.java +++ b/commons/src/main/java/org/georchestra/security/model/Organization.java @@ -67,6 +67,9 @@ public class Organization implements Serializable { private String mail; + /** Custom field added by georchestra.ldif file */ + private String orgUniqueId; + /** * String that somehow represents the current version, may be a timestamp, a * hash, etc. Provided by request header {@code sec-lastupdated} diff --git a/console/package-lock.json b/console/package-lock.json new file mode 100644 index 0000000000..48e341a095 --- /dev/null +++ b/console/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +} diff --git a/console/src/main/java/org/georchestra/console/ws/backoffice/orgs/OrgsController.java b/console/src/main/java/org/georchestra/console/ws/backoffice/orgs/OrgsController.java index db2185e942..1a6a165275 100644 --- a/console/src/main/java/org/georchestra/console/ws/backoffice/orgs/OrgsController.java +++ b/console/src/main/java/org/georchestra/console/ws/backoffice/orgs/OrgsController.java @@ -168,6 +168,25 @@ public Org getOrgInfos(@PathVariable String cn) { return this.orgDao.findByCommonName(cn); } + /** + * Retreive full information about one org as JSON document from unique + * organization id number (e.g french SIRET number). Following keys will be + * available : + * + * * 'id' (not used) * 'name' * 'shortName' * 'cities' as json array ex: + * [654,865498,98364,9834534,984984,6978984,98498] * 'status' * 'orgType' * + * 'address' * 'members' as json array ex: ["testadmin", "testuser"] + * + */ + @RequestMapping(value = REQUEST_MAPPING + + "/uoi/{orgUniqueId:.+}", method = RequestMethod.GET, produces = "application/json; charset=utf-8") + @ResponseBody + public Org getOrgInfosFromUniqueOrgId(@PathVariable String orgUniqueId) { + Org orgInfos = this.orgDao.findByOrgUniqueId(orgUniqueId); + this.checkOrgAuthorization(orgInfos.getId()); + return orgInfos; + } + /** * Update information of one org * @@ -185,6 +204,9 @@ public Org getOrgInfos(@PathVariable String cn) { * plante, 73059 Chambrille", "members": [ "testadmin", "testuser" ] } * */ + /** + * TODO: Control orgUniqueId unicity + */ @RequestMapping(value = REQUEST_MAPPING + "/{commonName:.+}", method = RequestMethod.PUT, produces = "application/json; charset=utf-8") @ResponseBody @@ -196,6 +218,10 @@ public Org updateOrgInfos(@PathVariable String commonName, HttpServletRequest re // Parse Json JSONObject json = this.parseRequest(request); + if (!this.validation.validateOrgUnicity(json)) { + throw new IOException("Organization : already exists"); + } + // Validate request against required fields for admin part if (!this.validation.validateOrgField("name", json)) { throw new IOException("required field : name"); @@ -258,6 +284,10 @@ public Org createOrg(HttpServletRequest request) throws IOException, JSONExcepti // Parse Json JSONObject json = this.parseRequest(request); + if (!this.validation.validateOrgUnicity(json)) { + throw new IOException("An organization with this identification number already exists."); + } + // Validate request against required fields for admin part if (!this.validation.validateOrgField("shortName", json)) { throw new IOException("required field : shortName"); @@ -482,6 +512,7 @@ protected void updateFromRequest(Org org, JSONObject json) throws IOException { org.setUrl(json.optString(Org.JSON_URL)); org.setLogo(json.optString(Org.JSON_LOGO)); org.setMail(json.optString(Org.JSON_MAIL)); + org.setOrgUniqueId(json.optString(Org.JSON_ORG_UNIQ_ID)); } /** diff --git a/console/src/main/java/org/georchestra/console/ws/editorgdetails/EditOrgDetailsFormBean.java b/console/src/main/java/org/georchestra/console/ws/editorgdetails/EditOrgDetailsFormBean.java index 4858facfa6..c3eb85e9f6 100644 --- a/console/src/main/java/org/georchestra/console/ws/editorgdetails/EditOrgDetailsFormBean.java +++ b/console/src/main/java/org/georchestra/console/ws/editorgdetails/EditOrgDetailsFormBean.java @@ -12,4 +12,5 @@ private String url; private String orgType; private String mail; + private String orgUniqueId; } diff --git a/console/src/main/java/org/georchestra/console/ws/editorgdetails/EditOrgDetailsFormController.java b/console/src/main/java/org/georchestra/console/ws/editorgdetails/EditOrgDetailsFormController.java index af8ceed65d..abee2b06d8 100644 --- a/console/src/main/java/org/georchestra/console/ws/editorgdetails/EditOrgDetailsFormController.java +++ b/console/src/main/java/org/georchestra/console/ws/editorgdetails/EditOrgDetailsFormController.java @@ -54,7 +54,8 @@ public class EditOrgDetailsFormController { private OrgsDao orgsDao; private Validation validation; - private static final String[] FIELDS = { "id", "url", "description", "logo", "name", "address", "mail" }; + private static final String[] FIELDS = { "id", "url", "description", "logo", "name", "address", "mail", + "orgUniqueId" }; private static final Log LOG = LogFactory.getLog(EditOrgDetailsFormController.class.getName()); @@ -94,6 +95,7 @@ public String setupForm(HttpServletRequest request, Model model) { model.addAttribute("id", org.getId()); model.addAttribute("logo", org.getLogo()); model.addAttribute("mail", org.getMail()); + model.addAttribute("orgUniqueId", org.getOrgUniqueId()); HttpSession session = request.getSession(); for (String f : FIELDS) { if (validation.isOrgFieldRequired(f)) { @@ -110,6 +112,7 @@ public String edit(Model model, @ModelAttribute EditOrgDetailsFormBean formBean, validation.validateOrgField("url", formBean.getUrl(), resultErrors); validation.validateOrgField("address", formBean.getAddress(), resultErrors); validation.validateOrgField("description", formBean.getDescription(), resultErrors); + validation.validateOrgField("orgUniqueId", formBean.getOrgUniqueId(), resultErrors); // TODO validate mail address for the organization ? if (resultErrors.hasErrors()) { @@ -122,6 +125,7 @@ public String edit(Model model, @ModelAttribute EditOrgDetailsFormBean formBean, orgOrigin.setDescription(formBean.getDescription()); orgOrigin.setUrl(formBean.getUrl()); orgOrigin.setAddress(formBean.getAddress()); + orgOrigin.setOrgUniqueId(formBean.getOrgUniqueId()); if (!logo.isEmpty()) { orgOrigin.setLogo(transformLogoFileToBase64(logo)); @@ -154,6 +158,7 @@ private EditOrgDetailsFormBean createForm(Org org) { formBean.setAddress(org.getAddress()); formBean.setOrgType(org.getOrgType()); formBean.setMail(org.getMail()); + formBean.setOrgUniqueId(org.getOrgUniqueId()); return formBean; } @@ -192,6 +197,11 @@ protected void logOrgDetailsChanges(Org org, EditOrgDetailsFormBean formBean, Mu if (StringUtils.isNotEmpty(org.getMail()) && !org.getMail().equals(formBean.getMail())) { logUtils.createAndLogDetails(id, Org.JSON_MAIL, org.getMail(), formBean.getMail(), type); } + + if (!org.getOrgUniqueId().equals(formBean.getOrgUniqueId())) { + logUtils.createAndLogDetails(id, Org.JSON_ORG_UNIQ_ID, org.getOrgUniqueId(), formBean.getAddress(), type); + } + } } \ No newline at end of file diff --git a/console/src/main/java/org/georchestra/console/ws/newaccount/AccountFormBean.java b/console/src/main/java/org/georchestra/console/ws/newaccount/AccountFormBean.java index 7c57c15340..6bf5d5844d 100644 --- a/console/src/main/java/org/georchestra/console/ws/newaccount/AccountFormBean.java +++ b/console/src/main/java/org/georchestra/console/ws/newaccount/AccountFormBean.java @@ -87,6 +87,8 @@ public class AccountFormBean implements Serializable { private @Getter @Setter String orgMail; + private @Getter @Setter String orgUniqueId; + public boolean getPrivacyPolicyAgreed() { return privacyPolicyAgreed; } diff --git a/console/src/main/java/org/georchestra/console/ws/newaccount/NewAccountFormController.java b/console/src/main/java/org/georchestra/console/ws/newaccount/NewAccountFormController.java index 41f68a95ea..c8131165ed 100644 --- a/console/src/main/java/org/georchestra/console/ws/newaccount/NewAccountFormController.java +++ b/console/src/main/java/org/georchestra/console/ws/newaccount/NewAccountFormController.java @@ -179,8 +179,8 @@ public AccountFormBean getAccountFormBean() { public void initForm(WebDataBinder dataBinder) { dataBinder.setAllowedFields("firstName", "surname", "email", "phone", "org", "title", "description", "uid", "password", "confirmPassword", "privacyPolicyAgreed", "consentAgreed", "createOrg", "orgName", - "orgShortName", "orgAddress", "orgType", "orgCities", "orgDescription", "orgUrl", "orgMail", "orgLogo", - "recaptcha_response_field"); + "orgShortName", "orgUniqueId", "orgAddress", "orgType", "orgCities", "orgDescription", "orgUrl", + "orgMail", "orgLogo", "recaptcha_response_field"); } @RequestMapping(value = "/account/new", method = RequestMethod.GET) @@ -258,6 +258,7 @@ public String create(HttpServletRequest request, @ModelAttribute AccountFormBean org.setUrl(formBean.getOrgUrl()); org.setLogo(formBean.getOrgLogo()); org.setMail(formBean.getOrgMail()); + org.setOrgUniqueId(formBean.getOrgUniqueId()); // Parse and store cities orgCities = orgCities.trim(); if (orgCities.length() > 0) @@ -409,6 +410,7 @@ private void validateFields(@ModelAttribute AccountFormBean formBean, BindingRes validation.validateUserField("title", formBean.getTitle(), result); validation.validateUserField("description", formBean.getDescription(), result); + // unique orgUniqueId value if (formBean.getCreateOrg() && !result.hasErrors()) { validation.validateOrgField("name", formBean.getOrgName(), result); validation.validateOrgField("shortName", formBean.getOrgShortName(), result); @@ -417,7 +419,10 @@ private void validateFields(@ModelAttribute AccountFormBean formBean, BindingRes validation.validateOrgField("url", formBean.getOrgUrl(), result); validation.validateOrgField("description", formBean.getOrgDescription(), result); validation.validateOrgField("logo", formBean.getOrgLogo(), result); + validation.validateOrgField("orgUniqueId", formBean.getOrgUniqueId(), result); validation.validateUrlFieldWithSpecificMsg("orgUrl", formBean.getOrgUrl(), result); + + validation.validateOrgUniqueIdField(formBean.getOrgUniqueId(), null, result); } else { validation.validateUserField("org", formBean.getOrg(), result); } diff --git a/console/src/main/java/org/georchestra/console/ws/utils/Validation.java b/console/src/main/java/org/georchestra/console/ws/utils/Validation.java index 3b78143c81..b781df752c 100644 --- a/console/src/main/java/org/georchestra/console/ws/utils/Validation.java +++ b/console/src/main/java/org/georchestra/console/ws/utils/Validation.java @@ -22,12 +22,17 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.HashSet; +import java.util.Objects; import java.util.Set; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.georchestra.ds.orgs.Org; +import org.georchestra.ds.orgs.OrgsDao; import org.json.JSONException; import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.validation.Errors; @@ -45,6 +50,9 @@ */ public class Validation { + @Autowired + private OrgsDao orgDao; + private Set requiredUserFields; private Set requiredOrgFields; @@ -191,4 +199,41 @@ public boolean validateUrlFieldWithSpecificMsg(String fullyQualifiedField, Strin } return true; } + + public boolean validateOrgUnicityByUniqueId(String orgUniqueId, String uuid) { + // case - not value to verify + if (orgUniqueId == null || orgUniqueId.isEmpty()) { + return true; + } + // test if org with same value already exists + Org findByOrgUniqueId = this.orgDao.findByOrgUniqueId(orgUniqueId); + // No org exists with this field value + if (findByOrgUniqueId == null) { + return true; + } + // No uuid to compare means that's an org creation + // and at this step, an org already exists with this orgUniqueId + if (uuid == null) { + // we can't validate this orgUniqueId that already exists + return false; + } + // Control if this is same org update + return Objects.equals(findByOrgUniqueId.getUniqueIdentifier(), UUID.fromString(uuid)); + } + + public boolean validateOrgUniqueIdField(String orgUniqueId, String uniqueId, Errors errors) { + if (!this.validateOrgUnicityByUniqueId(orgUniqueId, uniqueId)) { + errors.rejectValue("orgUniqueId", "error.orgUniqueIdExists", "orgUniqueIdExists"); + return false; + } + return true; + } + + public boolean validateOrgUnicity(JSONObject json) { + boolean isUniqueOrg = true; + if (json.has("orgUniqueId")) { + isUniqueOrg = this.validateOrgUnicityByUniqueId(json.getString("orgUniqueId"), json.getString("uuid")); + } + return isUniqueOrg; + } } diff --git a/console/src/main/webapp/WEB-INF/i18n/application.properties b/console/src/main/webapp/WEB-INF/i18n/application.properties index bdbaead441..284fca9557 100644 --- a/console/src/main/webapp/WEB-INF/i18n/application.properties +++ b/console/src/main/webapp/WEB-INF/i18n/application.properties @@ -94,6 +94,7 @@ confirmPassword.error.pwdNotEquals=These passwords don\'t match confirmPassword.error.pwdNotEquals.tag=Mismatch description.label=Description description.placeholder=Description +orgUniqueId.label=Identification number email.label=E-mail email.placeholder=E-mail email.error.required=Required @@ -101,6 +102,7 @@ email.error.invalidFormat=Invalid format email.error.exist=This e-mail is already in use, you can try to reset your password. error.required=Required error.badUrl=malformed url +error.orgUniqueIdExists=An organisation with this identification number already exists. facsimile.label=Fax facsimile.placeholder=Fax firstName.label=First Name @@ -113,6 +115,7 @@ org.cannot_find_org_in_list=My organization is not present org.required=Required org.creation.label=Organization Name org.creation.shortLabel=Short Name +org.creation.orgUniqueId=Identification number org.creation.address=Address org.creation.orgType=Organization type org.creation.orgDescription=Description diff --git a/console/src/main/webapp/WEB-INF/i18n/application_de.properties b/console/src/main/webapp/WEB-INF/i18n/application_de.properties index 8a71a4e292..49271b785c 100644 --- a/console/src/main/webapp/WEB-INF/i18n/application_de.properties +++ b/console/src/main/webapp/WEB-INF/i18n/application_de.properties @@ -93,12 +93,14 @@ confirmPassword.error.pwdNotEquals.tag=Nicht das gleiche Passwort description.label=Beschreibung description.placeholder=Beschreibung email.label=E-Mail +orgUniqueId.label=Identifikationsnummer email.placeholder=E-Mail email.error.required=Notwendig email.error.invalidFormat=Ungültiges Format email.error.exist=Diese E-Mail Adresse ist bereits in Benutzung, Sie können ihr Passwort zurücksetzen. error.required=Notwendig error.badUrl=malformed url +error.orgUniqueIdExists=Eine Organisation mit dieser Identifikationsnummer existiert bereits. facsimile.label=Fax facsimile.placeholder=Fax firstName.label=Vorname @@ -111,6 +113,7 @@ org.cannot_find_org_in_list=Meine Organisation ist nicht vorhanden org.required=Notwendig org.creation.label=Organisations-Name org.creation.shortLabel=Kurzbezeichnung +org.creation.orgUniqueId=Identifikationsnummer org.creation.address=Adresse org.creation.orgType=Organisationstyp org.creation.orgDescription=Beschreibung diff --git a/console/src/main/webapp/WEB-INF/i18n/application_es.properties b/console/src/main/webapp/WEB-INF/i18n/application_es.properties index 2acb8022cf..dea276008e 100644 --- a/console/src/main/webapp/WEB-INF/i18n/application_es.properties +++ b/console/src/main/webapp/WEB-INF/i18n/application_es.properties @@ -92,12 +92,14 @@ confirmPassword.error.pwdNotEquals.tag=Diferentes description.label=Descripción description.placeholder=Descripción email.label=dirección de correo electrónico +orgUniqueId.label=Identificación email.placeholder=dirección de correo electrónico email.error.required=Requerido email.error.invalidFormat=Formato inválido email.error.exist=Este correo electrónico ya está en uso, puede intentar restablecer su contraseña. error.required=Requerido error.badUrl=malformed url +error.orgUniqueIdExists=Ya existe una organización con este número de identificación. facsimile.label=Fax facsimile.placeholder=Fax firstName.label=Nombre @@ -110,6 +112,7 @@ org.cannot_find_org_in_list=Mi organización no esta presente org.required=Requerida org.creation.label=Nombre de la Organización org.creation.shortLabel=Nombre corto +org.creation.orgUniqueId=Número de identificación org.creation.address=Dirección org.creation.orgType=Tipo de Organización org.creation.orgDescription=Descripción diff --git a/console/src/main/webapp/WEB-INF/i18n/application_fr.properties b/console/src/main/webapp/WEB-INF/i18n/application_fr.properties index fde13ef0ec..b2bfc1fc3e 100644 --- a/console/src/main/webapp/WEB-INF/i18n/application_fr.properties +++ b/console/src/main/webapp/WEB-INF/i18n/application_fr.properties @@ -92,6 +92,7 @@ confirmPassword.error.pwdNotEquals=Les mots de passe sont différents confirmPassword.error.pwdNotEquals.tag=Différents description.label=Description description.placeholder=Description +orgUniqueId.label=Numéro d'identification email.label=Courriel email.placeholder=Courriel email.error.required=Requis @@ -99,6 +100,7 @@ email.error.invalidFormat=Format invalide email.error.exist=Ce courriel est déjà utilisé, vous pouvez tenter de réinitialiser votre mot de passe. error.required=Requis error.badUrl=Format d'url invalide +error.orgUniqueIdExists=Une organisation avec ce numéro d'identification existe déjà. facsimile.label=Fax facsimile.placeholder=Fax firstName.label=Prénom @@ -111,12 +113,14 @@ org.cannot_find_org_in_list=Mon organisme n'apparaît pas dans la liste org.required=Requis org.creation.label=Votre organisme org.creation.shortLabel=Libellé court +org.creation.orgUniqueId=Numéro d'identification org.creation.address=Adresse org.creation.orgType=Type d\'organisme org.creation.orgDescription=Description org.creation.orgUrl=Url org.creation.orgMail=Mail org.creation.orgLogo=Logo +org.creation.orgUniqueId=Numéro d'identification org.shortNameFormat=Le nom court ne doit comporter que des caractères alphanumériques password.label=Mot de passe password.placeholder=Mot de passe diff --git a/console/src/main/webapp/WEB-INF/i18n/application_nl.properties b/console/src/main/webapp/WEB-INF/i18n/application_nl.properties index 70eca33df3..4385cd58d0 100644 --- a/console/src/main/webapp/WEB-INF/i18n/application_nl.properties +++ b/console/src/main/webapp/WEB-INF/i18n/application_nl.properties @@ -93,12 +93,14 @@ confirmPassword.error.pwdNotEquals.tag=Verschillend description.label=Beschrijving description.placeholder=Beschrijving email.label=Email +orgUniqueId.label=Identificatienummer email.placeholder=Email email.error.required=Verplicht email.error.invalidFormat=Ongeldig formaat email.error.exist=Deze e-mail is al in gebruik, u kunt proberen om uw wachtwoord opnieuw in te stellen error.required=Verplicht error.badUrl=malformed url +error.orgUniqueIdExists=Er bestaat al een organisatie met dit identificatienummer. facsimile.label=Fax facsimile.placeholder=Fax firstName.label=Voornaam @@ -111,6 +113,7 @@ org.cannot_find_org_in_list=Mijn organisatie verschijnt niet in de lijst org.required=Verplicht org.creation.label=Uw organisatie org.creation.shortLabel=Kort label +org.creation.orgUniqueId=Identificatienummer org.creation.address=Adres org.creation.orgType=Type organisatie org.creation.orgDescription=Description diff --git a/console/src/main/webapp/WEB-INF/views/createAccountForm.jsp b/console/src/main/webapp/WEB-INF/views/createAccountForm.jsp index c5230397ae..875ad7cccb 100644 --- a/console/src/main/webapp/WEB-INF/views/createAccountForm.jsp +++ b/console/src/main/webapp/WEB-INF/views/createAccountForm.jsp @@ -108,6 +108,10 @@ document.querySelector('#orgShortName').setAttribute('title', '') + + + + diff --git a/console/src/main/webapp/WEB-INF/views/editOrgDetailsForm.jsp b/console/src/main/webapp/WEB-INF/views/editOrgDetailsForm.jsp index e6d1116885..e422c93182 100644 --- a/console/src/main/webapp/WEB-INF/views/editOrgDetailsForm.jsp +++ b/console/src/main/webapp/WEB-INF/views/editOrgDetailsForm.jsp @@ -88,6 +88,9 @@ + + +
diff --git a/console/src/main/webapp/manager/app/assets/lang/en.json b/console/src/main/webapp/manager/app/assets/lang/en.json index 80d33cfb9a..f5b43c85fd 100644 --- a/console/src/main/webapp/manager/app/assets/lang/en.json +++ b/console/src/main/webapp/manager/app/assets/lang/en.json @@ -111,6 +111,7 @@ "org.description" : "Description", "org.url" : "Website", "org.mail" : "Mail", + "org.orgUniqueId": "Identification number", "org.logo" : "Logo", "org.note" : "Internal Notes", "org.cities" : "Area", diff --git a/console/src/main/webapp/manager/app/assets/lang/fr.json b/console/src/main/webapp/manager/app/assets/lang/fr.json index 962182e12f..025bc2e384 100644 --- a/console/src/main/webapp/manager/app/assets/lang/fr.json +++ b/console/src/main/webapp/manager/app/assets/lang/fr.json @@ -111,6 +111,7 @@ "org.description" : "Description", "org.url" : "Site web", "org.mail" : "Mail", + "org.orgUniqueId": "Numéro d'identification", "org.logo" : "Logo", "org.note" : "Notes Internes", "org.cities" : "Aire de compétence", diff --git a/console/src/main/webapp/manager/app/components/orgs/orgs.es6 b/console/src/main/webapp/manager/app/components/orgs/orgs.es6 index c74763ee47..d6d143f0a5 100644 --- a/console/src/main/webapp/manager/app/components/orgs/orgs.es6 +++ b/console/src/main/webapp/manager/app/components/orgs/orgs.es6 @@ -20,7 +20,7 @@ class OrgsController { delete org.members }) this.simplifiedOrgs = this.orgs.map((org) => { - return { id: org.id, name: org.name, shortName: org.shortName, membersCount: org.membersCount, pending: org.pending, status: org.status } + return { id: org.id, name: org.name, shortName: org.shortName, membersCount: org.membersCount, pending: org.pending, status: org.status, orgUniqueId: org.orgUniqueId } }) }) diff --git a/console/src/main/webapp/manager/app/templates/orgForm.tpl.html b/console/src/main/webapp/manager/app/templates/orgForm.tpl.html index 6aaa564793..035db5d099 100644 --- a/console/src/main/webapp/manager/app/templates/orgForm.tpl.html +++ b/console/src/main/webapp/manager/app/templates/orgForm.tpl.html @@ -75,6 +75,13 @@ placeholder="" ng-required="required.mail">
+
+ +
+ +
+
diff --git a/console/src/main/webapp/manager/brunch-config.js b/console/src/main/webapp/manager/brunch-config.js index f052c9ad60..8f50184993 100644 --- a/console/src/main/webapp/manager/brunch-config.js +++ b/console/src/main/webapp/manager/brunch-config.js @@ -1,5 +1,11 @@ module.exports = { config: { + // Changer le port par défaut ici + server: { + port: 4000, // Changer 4000 par le port de votre choix + path: 'http://localhost:4000', + run: true + }, plugins: { ng_templates: { module: 'manager', diff --git a/console/src/main/webapp/manager/package-lock.json b/console/src/main/webapp/manager/package-lock.json index 03ac455958..5a8b18b8b4 100644 --- a/console/src/main/webapp/manager/package-lock.json +++ b/console/src/main/webapp/manager/package-lock.json @@ -809,7 +809,7 @@ } }, "@babel/traverse": { - "version": "7.23.2", + "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", "dev": true, @@ -1511,7 +1511,7 @@ } }, "browserify-sign": { - "version": "4.2.2", + "version": "4.2.1", "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", "dev": true, @@ -2219,7 +2219,7 @@ "dev": true }, "decode-uri-component": { - "version": "0.2.2", + "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true @@ -4511,7 +4511,7 @@ } }, "minimist": { - "version": "1.2.8", + "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true @@ -5395,7 +5395,7 @@ "dev": true }, "qs": { - "version": "6.4.1", + "version": "6.4.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", "dev": true, @@ -5713,7 +5713,7 @@ } }, "requirejs": { - "version": "2.3.7", + "version": "2.3.6", "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==", "dev": true @@ -6986,7 +6986,7 @@ "dev": true }, "word-wrap": { - "version": "1.2.4", + "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true diff --git a/console/src/test/java/org/georchestra/console/integration/OrgsIT.java b/console/src/test/java/org/georchestra/console/integration/OrgsIT.java index 207e7e5ac5..aa639a1cbe 100644 --- a/console/src/test/java/org/georchestra/console/integration/OrgsIT.java +++ b/console/src/test/java/org/georchestra/console/integration/OrgsIT.java @@ -71,6 +71,7 @@ public class OrgsIT extends ConsoleIntegrationTest { support.perform(get("/private/orgs/" + orgName.replace(" ", "_"))) .andExpect(jsonPath("$.id").value(orgName.replace(" ", "_").toLowerCase())) .andExpect(jsonPath("$.shortName").value(orgName.toLowerCase())) + .andExpect(jsonPath("$.orgUniqueId").value("80908401500035")) .andExpect(jsonPath("$.name").value("camptocamp")).andExpect(jsonPath("$.cities").isEmpty()) .andExpect(jsonPath("$.members").isEmpty()).andExpect(jsonPath("$.address").value("1, rue du pont")) .andExpect(jsonPath("$.orgType").value("Company")).andExpect(jsonPath("$.pending").value(false)); diff --git a/console/src/test/resources/testData/createOrgPayload.json b/console/src/test/resources/testData/createOrgPayload.json index 6a5d7234bc..55407d762b 100644 --- a/console/src/test/resources/testData/createOrgPayload.json +++ b/console/src/test/resources/testData/createOrgPayload.json @@ -2,5 +2,6 @@ "address": "1, rue du pont", "name": "camptocamp", "orgType": "Company", - "shortName": "{shortName}" + "shortName": "{shortName}", + "orgUniqueId": "80908401500035" } \ No newline at end of file diff --git a/ldap-account-management/src/main/java/org/georchestra/ds/orgs/Org.java b/ldap-account-management/src/main/java/org/georchestra/ds/orgs/Org.java index a28393eca5..aac0829a63 100644 --- a/ldap-account-management/src/main/java/org/georchestra/ds/orgs/Org.java +++ b/ldap-account-management/src/main/java/org/georchestra/ds/orgs/Org.java @@ -59,6 +59,7 @@ public class Org extends ReferenceAware implements Comparable, Cloneable { public static final String JSON_ADDRESS = "address"; public static final String JSON_ORG_TYPE = "orgType"; public static final String JSON_MAIL = "mail"; + public static final String JSON_ORG_UNIQ_ID = "orgUniqueId"; private String id; private String name; @@ -180,4 +181,13 @@ public String getMail() { public void setMail(String mail) { this.ext.setMail(mail); } + + @JsonProperty(JSON_ORG_UNIQ_ID) + public String getOrgUniqueId() { + return this.ext.getOrgUniqueId(); + } + + public void setOrgUniqueId(String orgUniqueId) { + this.ext.setOrgUniqueId(orgUniqueId); + } } diff --git a/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgExt.java b/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgExt.java index f7aae8321f..a718f28140 100644 --- a/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgExt.java +++ b/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgExt.java @@ -47,6 +47,7 @@ class OrgExt extends ReferenceAware implements Cloneable { private String logo = ""; private String note = ""; private String mail = ""; + private String orgUniqueId = ""; @Override public OrgExt clone() { diff --git a/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgsDao.java b/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgsDao.java index b8bca51068..459b2675e7 100644 --- a/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgsDao.java +++ b/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgsDao.java @@ -56,6 +56,8 @@ public interface OrgsDao { public Org findByUser(Account user); + public Org findByOrgUniqueId(String orgUniqueId); + /** * Search by {@link Org#getUniqueIdentifier()} * diff --git a/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgsDaoImpl.java b/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgsDaoImpl.java index f1a7567ae2..9b88bbffe2 100644 --- a/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgsDaoImpl.java +++ b/ldap-account-management/src/main/java/org/georchestra/ds/orgs/OrgsDaoImpl.java @@ -203,7 +203,9 @@ public Org mapFromAttributes(Attributes attrs) throws NamingException { org.setMembers(asStringStream(attrs, "member").map(LdapNameBuilder::newInstance) .map(LdapNameBuilder::build).map(name -> name.getRdn(name.size() - 1).getValue().toString()) .collect(Collectors.toList())); + org.setOrgUniqueId(asStringStream(attrs, "orgUniqueId").collect(joining(","))); org.setPending(pending); + return org; } }; @@ -227,6 +229,7 @@ public void mapPayloadToContext(OrgExt org, DirContextOperations context) { setOrDeleteField(context, "description", org.getDescription()); setOrDeleteField(context, "labeledURI", org.getUrl()); setOrDeletePhoto(context, "jpegPhoto", org.getLogo()); + setOrDeleteField(context, "orgUniqueId", org.getOrgUniqueId()); } @Override @@ -258,6 +261,7 @@ public OrgExt mapFromAttributes(Attributes attrs) throws NamingException { orgExt.setLogo(asPhoto(attrs.get("jpegPhoto"))); orgExt.setPending(pending); orgExt.setMail(asString(attrs.get("mail"))); + orgExt.setOrgUniqueId(asString(attrs.get("orgUniqueId"))); return orgExt; } @@ -396,6 +400,12 @@ public Org findById(UUID uuid) { return findAllWithExt().filter(o -> uuid.equals(o.getUniqueIdentifier())).findFirst().orElse(null); } + @Override + public Org findByOrgUniqueId(String orgUniqueId) { + return findAllWithExt().filter(o -> orgUniqueId.equals(o.getOrgUniqueId())).findFirst().orElse(null); + + } + private Org addExt(Org org) { if (org == null) { return null; diff --git a/ldap-account-management/src/main/java/org/georchestra/ds/security/OrganizationMapper.java b/ldap-account-management/src/main/java/org/georchestra/ds/security/OrganizationMapper.java index 6cbec19bec..a711eb74a0 100644 --- a/ldap-account-management/src/main/java/org/georchestra/ds/security/OrganizationMapper.java +++ b/ldap-account-management/src/main/java/org/georchestra/ds/security/OrganizationMapper.java @@ -39,6 +39,7 @@ public interface OrganizationMapper { @Mapping(target = "linkage", source = "url") @Mapping(target = "postalAddress", source = "address") @Mapping(target = "category", source = "orgType") + @Mapping(target = "orgUniqueId", source = "orgUniqueId", ignore = true) @Mapping(target = "lastUpdated", ignore = true) @Mapping(target = "withId", ignore = true) @Mapping(target = "withShortName", ignore = true) @@ -51,6 +52,7 @@ public interface OrganizationMapper { @Mapping(target = "withLastUpdated", ignore = true) @Mapping(target = "withMembers", ignore = true) @Mapping(target = "withMail", source = "mail", ignore = true) + @Mapping(target = "withOrgUniqueId", source = "orgUniqueId", ignore = true) Organization map(Org org); @AfterMapping diff --git a/ldap-account-management/src/main/java/org/georchestra/ds/security/OrganizationsApiImpl.java b/ldap-account-management/src/main/java/org/georchestra/ds/security/OrganizationsApiImpl.java index 19ffe6de93..d10d64b260 100644 --- a/ldap-account-management/src/main/java/org/georchestra/ds/security/OrganizationsApiImpl.java +++ b/ldap-account-management/src/main/java/org/georchestra/ds/security/OrganizationsApiImpl.java @@ -66,6 +66,13 @@ public Optional findByShortName(String shortName) { .map(orgMapper::map); } + @Override + public Optional findByOrgUniqueId(String orgUniqueId) { + return Optional.ofNullable(orgsDao.findByOrgUniqueId(orgUniqueId))// + .filter(not(Org::isPending))// + .map(orgMapper::map); + } + @Override public Optional getLogo(String id) { UUID uuid = UUID.fromString(id); diff --git a/ldap-account-management/src/test/java/org/georchestra/ds/orgs/OrgsDaoImplIT.java b/ldap-account-management/src/test/java/org/georchestra/ds/orgs/OrgsDaoImplIT.java index d9769fcc29..cac6733616 100644 --- a/ldap-account-management/src/test/java/org/georchestra/ds/orgs/OrgsDaoImplIT.java +++ b/ldap-account-management/src/test/java/org/georchestra/ds/orgs/OrgsDaoImplIT.java @@ -50,6 +50,7 @@ public void setup() throws Exception { org.setShortName("tEsTOrG"); org.setCities(Lists.newArrayList("Paris")); org.setOrgType("Non Profit"); + org.setOrgUniqueId("5315431354"); dao.insert(org); @@ -59,6 +60,7 @@ public void setup() throws Exception { pendingOrg.setName("Pending Org"); pendingOrg.setPending(true); pendingOrg.setOrgType("For Profit"); + pendingOrg.setOrgUniqueId("6887431324"); dao.insert(pendingOrg); } @@ -223,6 +225,7 @@ public void testOrgAttributeMapperRemovingAllCities() { ncOrg.setShortName("no cities org"); ncOrg.setCities(Lists.newArrayList("Paris")); ncOrg.setOrgType("Non Profit"); + ncOrg.setOrgUniqueId("41134144731"); dao.insert(ncOrg); ncOrg = dao.findByCommonName(ncOrg.getId()); ncOrg.setCities(List.of()); diff --git a/ldap/docker-root/georchestra.ldif b/ldap/docker-root/georchestra.ldif index c985c45839..6d8e199ee4 100644 --- a/ldap/docker-root/georchestra.ldif +++ b/ldap/docker-root/georchestra.ldif @@ -370,6 +370,7 @@ o: C2C mail: georchestra@camptocamp.com businessCategory: Company postalAddress: 18 Rue du lac Saint André, 73000 Chambéry +orgUniqueId: 43369857800054 labeledURI: https://www.camptocamp.com/ description: Camptocamp SAS France knowledgeInformation: Internal CRM notes on Camptocamp diff --git a/ldap/docker-root/georchestraSchema.ldif b/ldap/docker-root/georchestraSchema.ldif index b5c49182b3..2637ff875e 100644 --- a/ldap/docker-root/georchestraSchema.ldif +++ b/ldap/docker-root/georchestraSchema.ldif @@ -20,25 +20,31 @@ olcAttributeTypes: ( 1.3.6.1.4.1.53611.1.2.2 SINGLE-VALUE ) olcAttributeTypes: ( 1.3.6.1.4.1.53611.1.2.3 NAME 'oAuth2Provider' - DESC 'OAuth2 provider for external identity provider users)' + DESC 'OAuth2 provider for external identity provider users' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) olcAttributeTypes: ( 1.3.6.1.4.1.53611.1.2.4 NAME 'oAuth2Uid' - DESC 'OAuth2 UID for external identity provider users)' + DESC 'OAuth2 UID for external identity provider users' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.53611.1.2.5 + NAME 'orgUniqueId' + DESC 'organization identifier such as SIRET number or other' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + SINGLE-VALUE) olcObjectClasses: ( 1.3.6.1.4.1.53611.1.1.2 NAME 'georchestraOrg' DESC 'georchestra org' SUP top AUXILIARY - MAY (jpegphoto $ labeledURI $ knowledgeInformation $ georchestraObjectIdentifier)) + MAY (jpegphoto $ labeledURI $ knowledgeInformation $ georchestraObjectIdentifier $ orgUniqueId)) olcObjectClasses: ( 1.3.6.1.4.1.53611.1.1.3 NAME 'georchestraRole' DESC 'Uniquely identifiable georchestra role' SUP top AUXILIARY - MAY (georchestraObjectIdentifier)) + MAY (georchestraObjectIdentifier)) \ No newline at end of file