This is an automated email from the git hooks/post-receive script. New commit to branch feature/1_socialauth in repository pollen. See https://gitlab.nuiton.org/chorem/pollen.git commit 6ad03011d76b59ef512a3fcf88a235510b8e4323 Author: Kevin Morin <morin@codelutin.com> Date: Fri Aug 25 18:04:36 2017 +0200 refs #1 gestion des tiers de connexion + style du login --- pollen-ui-riot-js/src/main/web/css/main.css | 8 ++ pollen-ui-riot-js/src/main/web/i18n.json | 14 ++- pollen-ui-riot-js/src/main/web/js/AuthService.js | 18 ++- pollen-ui-riot-js/src/main/web/js/FetchService.js | 5 +- pollen-ui-riot-js/src/main/web/js/Session.js | 2 +- pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html | 131 ++++++++++++++------- pollen-ui-riot-js/src/main/web/tag/SignUp.tag.html | 4 +- .../src/main/web/tag/admin/LoginProviders.tag.html | 104 +++++++++++++--- 8 files changed, 217 insertions(+), 69 deletions(-) diff --git a/pollen-ui-riot-js/src/main/web/css/main.css b/pollen-ui-riot-js/src/main/web/css/main.css index 04db9045..59c2433c 100644 --- a/pollen-ui-riot-js/src/main/web/css/main.css +++ b/pollen-ui-riot-js/src/main/web/css/main.css @@ -470,3 +470,11 @@ pollenfooter a:hover { .no-border { border: 0; } + +.align-right { + text-align: right; +} + +.align-center { + text-align: center; + } \ No newline at end of file diff --git a/pollen-ui-riot-js/src/main/web/i18n.json b/pollen-ui-riot-js/src/main/web/i18n.json index 61efac9d..ce320eaa 100644 --- a/pollen-ui-riot-js/src/main/web/i18n.json +++ b/pollen-ui-riot-js/src/main/web/i18n.json @@ -545,7 +545,12 @@ "loginProviders_key": "Clé client", "loginProviders_secret": "Code secret", "loginProviders_permissions": "Permissions", - "loginProviders_active": "Actif" + "loginProviders_active": "Actif", + "loginProviders_newProvider": "Nouveau tiers", + "loginProviders_deleteMessage": "Êtes-vous sûr de vouloir supprimer ce tier ?", + "loginProviders_emptyName": "Le nom est obligatoire", + "loginProviders_emptyKey": "La clé client est obligatoire", + "loginProviders_emptySecret": "Le code secret est obligatoire" }, "en": { "main_pollen_title": "Pollen - ", @@ -1072,6 +1077,11 @@ "loginProviders_key": "Client key", "loginProviders_secret": "Secret code", "loginProviders_permissions": "Permissions", - "loginProviders_active": "Active" + "loginProviders_active": "Active", + "loginProviders_newProvider": "New provider", + "loginProviders_deleteMessage": "Are you sure you want to delete this provider?", + "loginProviders_emptyName": "The name is mandatory", + "loginProviders_emptyKey": "The client key is mandatory", + "loginProviders_emptySecret": "The secret code is mandatory" } } diff --git a/pollen-ui-riot-js/src/main/web/js/AuthService.js b/pollen-ui-riot-js/src/main/web/js/AuthService.js index 5aa63a94..3fd1d1f1 100644 --- a/pollen-ui-riot-js/src/main/web/js/AuthService.js +++ b/pollen-ui-riot-js/src/main/web/js/AuthService.js @@ -68,12 +68,15 @@ class AuthService extends FetchService { return this.post("/v1/resendValidation", email); } - signInProvider(query, providerRedirection) { + getLoginProviderUrl(providerId, redirection) { + return this.get("/v1/login/" + providerId, { providerRedirection: redirection}); + } + + signInProvider(query) { return this.fetch( "/v1/login/" + query.loginProvider, "POST", - {Authorization: JSON.stringify(query)}, - providerRedirection); + {Authorization: JSON.stringify(query)}); } getAllLoginProviders() { @@ -81,13 +84,20 @@ class AuthService extends FetchService { } getAvailableLoginProviders() { - console.log("getAvailableLoginProviders") + return this.get("/v1/loginproviders/available"); + } + + getActiveLoginProviders() { return this.get("/v1/loginproviders/active"); } saveLoginProvider(loginProvider) { return this.post("/v1/loginproviders/" + (loginProvider.id || ""), loginProvider); } + + deleteLoginProvider(loginProvider) { + return this.doDelete("/v1/loginproviders/" + loginProvider.id); + } } module.exports = singleton(AuthService); diff --git a/pollen-ui-riot-js/src/main/web/js/FetchService.js b/pollen-ui-riot-js/src/main/web/js/FetchService.js index 8966f29b..ccdbeb42 100644 --- a/pollen-ui-riot-js/src/main/web/js/FetchService.js +++ b/pollen-ui-riot-js/src/main/web/js/FetchService.js @@ -49,7 +49,10 @@ class FetchService { return null; } if (response.status === 200) { - return response.json(); + let responseCopy = response.clone(); + return responseCopy.json().catch(err => { + return response.text(); + }); } if (response.status === 400) { return response.json().then(json => Promise.reject(json)); diff --git a/pollen-ui-riot-js/src/main/web/js/Session.js b/pollen-ui-riot-js/src/main/web/js/Session.js index b2deb15e..5582ba2a 100644 --- a/pollen-ui-riot-js/src/main/web/js/Session.js +++ b/pollen-ui-riot-js/src/main/web/js/Session.js @@ -134,7 +134,7 @@ class Session { } signInProvider(query) { - return authService.signInProvider(query, this.getProviderRedirectionUrl(query.loginProvider)) + return authService.signInProvider(query) .then(auth => this.updateConnection(auth, this)); } diff --git a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html index c571e63a..f58786ac 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/SignIn.tag.html @@ -24,42 +24,45 @@ require("./components/HumanInput.tag.html"); <SignIn> <div class="body-container colors-default sign-in-layer" show={openSignIn}> <div class="body-content"> - <h1 class="c-heading">{__.title}</h1> + <h1 class="c-heading"><i class="fa fa-sign-in"></i> {__.title}</h1> <form class="signin"> <HumanInput onsubmit={signIn}/> <div class="o-form-element"> - <div class="c-input-group c-input-group--stacked"> - <div class="o-field"> - <input class="c-field {c-field--error : message}" - type="email" - id="login" - name="login" - ref="login" - required - placeholder={__.login_placeholder}> - </div> - <div class="o-field o-field--icon-right"> - <input class="c-field {c-field--error : message}" - type="password" - id="password" - name="password" - ref="password" - required - placeholder={__.password_placeholder}> - <button class="c-icon login-btn" - type="submit" - title={__.connexion}> - <i class="fa fa-fw fa-arrow-right"/> - </button> - </div> - </div> + <label class="c-label" for="login">{__.login}</label> + <input class="c-field {c-field--error : message}" + type="email" + id="login" + name="login" + ref="login" + required + placeholder={__.login_placeholder}/> + </div> + <div class="o-form-element"> + <label class="c-label" for="password">{__.password}</label> + <input class="c-field {c-field--error : message}" + type="password" + id="password" + name="password" + ref="password" + required + placeholder={__.password_placeholder}> + </div> + <div class="o-form-element align-right"> + <p><button class="c-button c-button--info" type="submit"><i class="fa fa-sign-in"></i> {__.title}</button></p> <div class="c-hint--static c-hint--error">{message}</div> + <p><a onclick="{newPassword}">{__.lostpassword}</a></p> + </div> + <div class="o-form-element align-center"> + <p>Ou connectez vous avec votre compte :</p> + <p> + <a each="{loginProvider in loginProviders}" class="provider-link" + onclick="{signinWithProvider(loginProvider)}"> + <i class="fa fa-{providerIcons[loginProvider]}" if="{providerIcons[loginProvider]}"></i> + <span if="{!providerIcons[loginProvider]}">{loginProvider}</span> + </a> + </p> </div> - <a onclick="{newPassword}">{__.lostpassword}</a> </form> - <p>Ou connectez vous avec votre compte : - <a each="{loginProvider in loginProviders}" onclick="{signinWithProvider(loginProvider)}">{loginProvider}</a> - </p> </div> <SignUp/> @@ -78,10 +81,25 @@ require("./components/HumanInput.tag.html"); this.message = ""; this.openSignIn = false; + this.providerIcons = { + "amazon": "amazon", + "facebook": "facebook-official", + "flickr": "flickr", + "foursquare": "foursquare", + "github": "github", + "googleplus": "google", + "instagram": "instagram", + "linkedin": "linkedin", + "linkedin2": "linkedin", + "stackexchange": "stack-exchange", + "twitter": "twitter", + "yahoo": "yahoo" + }; + let authService = require("../js/AuthService"); this.loginProviders = []; this.on("mount", () => { - authService.getAvailableLoginProviders().then((result) => { + authService.getActiveLoginProviders().then((result) => { this.loginProviders = result; this.update(); }); @@ -122,8 +140,11 @@ require("./components/HumanInput.tag.html"); this.signinWithProvider = (provider) => (e) => { let currentPage = location.hash || "#"; localStorage.setItem("currentPage", currentPage); - location.href = this.session.configuration.endPoint + "/v1/login/" + provider - + "?providerRedirection=" + encodeURIComponent(this.session.getProviderRedirectionUrl(provider)); + let authService = require("../js/AuthService"); + let redirection = encodeURIComponent(this.session.getProviderRedirectionUrl(provider)); + authService.getLoginProviderUrl(provider, redirection).then(result => { + location.href = result; + }); }; </script> @@ -143,21 +164,10 @@ require("./components/HumanInput.tag.html"); top: 10px; } - .signin { - width: 250px; - margin: 0 auto; - } - .c-heading { text-align: center; } - .login-btn { - border: none; - background: transparent; - font-size: 1em; - } - .body-content { margin-bottom: 20px; } @@ -168,6 +178,39 @@ require("./components/HumanInput.tag.html"); } } + .signin { + padding: 0 1em; + margin: 0 auto; + max-width: 450px; + } + + .o-form-element p { + padding: 2px 0; + } + + .provider-link { + font-size: 2em; + } + + @media (min-width: 640px) { + .o-form-element .c-label:first-child { + width: 35%; + display: inline-block; + text-align: right; + float: left; + padding-top: 0.5em; + padding-right: 5px; + } + + .o-form-element .c-field { + width: 65%; + display: inline-block; + } + + .signin .c-hint--static { + margin-left: 35%; + } + } </style> </SignIn> diff --git a/pollen-ui-riot-js/src/main/web/tag/SignUp.tag.html b/pollen-ui-riot-js/src/main/web/tag/SignUp.tag.html index eee9115a..1d830d41 100644 --- a/pollen-ui-riot-js/src/main/web/tag/SignUp.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/SignUp.tag.html @@ -95,8 +95,8 @@ require("./components/HumanInput.tag.html"); <div class="actions-right"> <button type="submit" class="c-button c-button--info"> - <i class="fa fa-plus" aria-hidden="true"></i> - {__.validate} + <i class="fa fa-user-plus" aria-hidden="true"></i> + {__.title} </button> </div> </form> diff --git a/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html b/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html index 5e23f89e..49e06b1c 100644 --- a/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html +++ b/pollen-ui-riot-js/src/main/web/tag/admin/LoginProviders.tag.html @@ -1,3 +1,5 @@ +require("../components/HumanInput.tag.html"); + <LoginProviders> <div class="container" show="{loaded}"> <h1>{__.title}</h1> @@ -7,29 +9,38 @@ <table> <thead> <tr> - <th>{__.name}</th> - <th>{__.key}</th> - <th>{__.secret}</th> - <th>{__.permission}</th> + <th>{__.name}*</th> + <th>{__.key}*</th> + <th>{__.secret}*</th> + <th>{__.permissions}</th> <th>{__.active}</th> </tr> </thead> <tbody> <tr each="{loginprovider, index in loginProviders}"> - <td><input type="text" ref="name{index}" value="{loginprovider.name}" required/></td> - <td><input type="text" ref="key{index}" value="{loginprovider.key}" required/></td> - <td><input type="text" ref="secret{index}" value="{loginprovider.secret}" required/></td> - <td><input type="text" ref="permissions{index}" value="{loginprovider.permissions}"/></td> - <td><input type="checkbox" ref="active{index}" checked="{loginprovider.active}"/></td> <td> - <button class="c-button" onclick="{saveLoginProvider(index)}"><i class="fa fa-check"></i></button> - <button class="c-button" onclick="{cancelEdition(index)}"><i class="fa fa-remove"></i></button> + <select class="c-field" ref="name{index}" required disabled="{editingRow != index}"> + <option>{loginprovider.name}</option> + <option each="{availableProvider in availableLoginProviders}">{availableProvider}</option> + </select> + </td> + <td><input class="c-field" type="text" ref="key{index}" value="{loginprovider.key}" required disabled="{editingRow != index}"/></td> + <td><input class="c-field c-field--large" type="text" ref="secret{index}" value="{loginprovider.secret}" required disabled="{editingRow != index}"/></td> + <td><input class="c-field" type="text" ref="permissions{index}" value="{loginprovider.permissions}" disabled="{editingRow != index}"/></td> + <td><input type="checkbox" ref="active{index}" checked="{loginprovider.active}" disabled="{editingRow != index}"/></td> + <td if="{editingRow != index}"> + <button class="c-button c-button--info" onclick="{editLoginProvider(index)}" disabled="{editingRow != null}"><i class="fa fa-edit"></i></button> + <button class="c-button c-button--error" onclick="{deleteLoginProvider(index)}" disabled="{editingRow != null}"><i class="fa fa-trash"></i></button> + </td> + <td if="{editingRow == index}"> + <button class="c-button c-button--success" onclick="{saveLoginProvider(index)}"><i class="fa fa-check"></i></button> + <button class="c-button c-button--error" onclick="{cancelEdition(index)}"><i class="fa fa-remove"></i></button> </td> </tr> </tbody> </table> - <button class="c-button" onclick="{addProvider}"><i class="fa fa-plus"></i></button> + <button class="c-button" onclick="{addProvider}" disabled="{editingRow != null}"><i class="fa fa-plus"></i> {__.newProvider}</button> </div> </div> @@ -38,27 +49,77 @@ let session = require("../../js/Session"); this.installBundle(session, "loginProviders"); + this.editingRow = null; + let authService = require("../../js/AuthService"); this.loginProviders = []; - authService.getAllLoginProviders().then((result) => { + this.availableLoginProviders = []; + Promise.all([authService.getAllLoginProviders(), authService.getAvailableLoginProviders()]).then(results => { if (!this.loaded) { - this.loginProviders = result; + this.loginProviders = results[0]; + let usedLoginProviders = Array.from(this.loginProviders, item => item.name); + this.availableLoginProviders = results[1].filter(item => usedLoginProviders.indexOf(item) === -1); + this.availableLoginProviders.sort(); this.loaded = true; this.update(); } - return result; }); this.addProvider = (e) => { e.preventDefault(); e.stopPropagation(); this.loginProviders.push({}); + this.editingRow = this.loginProviders.length - 1; + }; + + this.editLoginProvider = (index) => (e) => { + e.preventDefault(); + e.stopPropagation(); + this.editingRow = index; + }; + + this.deleteLoginProvider = (index) => (e) => { + e.preventDefault(); + e.stopPropagation(); + let loginProvider = this.loginProviders[index]; + this.confirm(this.__.deleteMessage).then((confirm) => { + if (confirm) { + if (!loginProvider.id) { + this.loginProviders.splice(index, 1); + this.availableLoginProviders.push(loginProvider.name); + this.availableLoginProviders.sort(); + this.update(); + } else { + authService.deleteLoginProvider(loginProvider).then(() => { + this.loginProviders.splice(index, 1); + this.availableLoginProviders.push(loginProvider.name); + this.availableLoginProviders.sort(); + this.update(); + }); + } + } + }); }; this.saveLoginProvider = (index) => (e) => { e.preventDefault(); e.stopPropagation(); let loginProvider = this.loginProviders[index]; + let oldProvider = loginProvider.name; + + if (!this.refs["name" + index].value) { + alert(this.__.emptyName); + return; + } + if (!this.refs["key" + index].value) { + alert(this.__.emptyKey); + return; + } + if (!this.refs["secret" + index].value) { + alert(this.__.emptySecret); + return; + } + loginProvider.name = this.refs["name" + index].value; loginProvider.key = this.refs["key" + index].value; loginProvider.secret = this.refs["secret" + index].value; @@ -72,6 +133,15 @@ loginProvider.secret = result.secret; loginProvider.permissions = result.permissions; loginProvider.active = result.active; + + this.availableLoginProviders.splice(this.availableLoginProviders.indexOf(result.name), 1); + this.availableLoginProviders.push(oldProvider); + this.availableLoginProviders.sort(); + + this.refs["name" + index].value = loginProvider.name; + + this.editingRow = null; + this.update(); }); }; @@ -84,9 +154,13 @@ this.refs["secret" + index].value = loginProvider.secret || ""; this.refs["permissions" + index].value = loginProvider.permissions || ""; this.refs["active" + index].checked = loginProvider.active || false; + this.editingRow = null; }; </script> <style> + td { + text-align: center; + } </style> </LoginProviders> -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.