{-# LANGUAGE QuasiQuotes #-} module Happstack.Authenticate.Password.Controllers where import Control.Concurrent.STM (atomically) import Control.Concurrent.STM.TVar (TVar, readTVar) import Control.Monad.Trans (MonadIO(liftIO)) import Data.Maybe (isJust, fromJust) import Data.Text (Text) import qualified Data.Text as T import Happstack.Authenticate.Core (AuthenticateConfig(_postLoginRedirect), AuthenticateURL) import Happstack.Authenticate.Password.URL (PasswordURL(Account, Token, Partial, PasswordReset, PasswordRequestReset), nestPasswordURL) import Happstack.Authenticate.Password.PartialsURL (PartialURL(ChangePassword, Logout, Login, LoginInline, SignupPassword, ResetPasswordForm, RequestResetPasswordForm)) import Language.Javascript.JMacro import Web.Routes usernamePasswordCtrl :: (MonadIO m) => TVar AuthenticateConfig -> RouteT AuthenticateURL m JStat usernamePasswordCtrl :: TVar AuthenticateConfig -> RouteT AuthenticateURL m JStat usernamePasswordCtrl TVar AuthenticateConfig authenticateConfigTV = RouteT PasswordURL m JStat -> RouteT AuthenticateURL m JStat forall (m :: * -> *) a. RouteT PasswordURL m a -> RouteT AuthenticateURL m a nestPasswordURL (RouteT PasswordURL m JStat -> RouteT AuthenticateURL m JStat) -> RouteT PasswordURL m JStat -> RouteT AuthenticateURL m JStat forall a b. (a -> b) -> a -> b $ do PasswordURL -> [(Text, Maybe Text)] -> Text fn <- RouteT PasswordURL m (PasswordURL -> [(Text, Maybe Text)] -> Text) forall (m :: * -> *). MonadRoute m => m (URL m -> [(Text, Maybe Text)] -> Text) askRouteFn Maybe Text plr <- IO (Maybe Text) -> RouteT PasswordURL m (Maybe Text) forall (m :: * -> *) a. MonadIO m => IO a -> m a liftIO (AuthenticateConfig -> Maybe Text _postLoginRedirect (AuthenticateConfig -> Maybe Text) -> IO AuthenticateConfig -> IO (Maybe Text) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> (STM AuthenticateConfig -> IO AuthenticateConfig forall a. STM a -> IO a atomically (STM AuthenticateConfig -> IO AuthenticateConfig) -> STM AuthenticateConfig -> IO AuthenticateConfig forall a b. (a -> b) -> a -> b $ TVar AuthenticateConfig -> STM AuthenticateConfig forall a. TVar a -> STM a readTVar TVar AuthenticateConfig authenticateConfigTV)) JStat -> RouteT PasswordURL m JStat forall (m :: * -> *) a. Monad m => a -> m a return (JStat -> RouteT PasswordURL m JStat) -> JStat -> RouteT PasswordURL m JStat forall a b. (a -> b) -> a -> b $ Maybe Text -> (PasswordURL -> [(Text, Maybe Text)] -> Text) -> JStat usernamePasswordCtrlJs Maybe Text plr PasswordURL -> [(Text, Maybe Text)] -> Text fn usernamePasswordCtrlJs :: Maybe Text -> (PasswordURL -> [(Text, Maybe Text)] -> Text) -> JStat usernamePasswordCtrlJs :: Maybe Text -> (PasswordURL -> [(Text, Maybe Text)] -> Text) -> JStat usernamePasswordCtrlJs Maybe Text postLoginRedirect PasswordURL -> [(Text, Maybe Text)] -> Text showURL = [jmacro| { var usernamePassword = angular.module('usernamePassword', ['happstackAuthentication']); usernamePassword.controller('UsernamePasswordCtrl', ['$scope','$http','$window', '$location', 'userService', function ($scope, $http, $window, $location, userService) { // login() emptyUser = function() { return { user: '', password: '' }; }; $scope.user = emptyUser(); $scope.login = function () { function callback(datum, status, headers, config) { if (datum == null) { $scope.username_password_error = 'error communicating with the server.'; } else { if (datum.jrStatus == "Ok") { $scope.username_password_error = ''; userService.updateFromToken(datum.jrData.token); `loginRedirect postLoginRedirect` } else { userService.clearUser(); $scope.username_password_error = datum.jrData; } } }; $http. post(`(showURL Token [])`, $scope.user). success(callback). error(callback); }; // signupPassword() emptySignup = function () { return { naUser: { username: '', email: '' }, naPassword: '', naPasswordConfirm: '' }; }; $scope.signup = emptySignup(); $scope.signupPassword = function () { $scope.signup.naUser.userId = 0; function callback(datum, status, headers, config) { if (datum == null) { $scope.username_password_error = 'error communicating with server.'; } else { if (datum.jrStatus == "Ok") { $scope.signup_error = 'Account Created'; // FIXME -- I18N $scope.signup = emptySignup(); } else { $scope.signup_error = datum.jrData; } } }; $http. post(`(showURL (Account Nothing) [])`, $scope.signup). success(callback). error(callback); }; // changePassword() emptyPassword = function () { return { cpOldPassword: '', cpNewPassword: '', cpNewPasswordConfirm: '' }; }; $scope.password = emptyPassword(); $scope.changePassword = function (url) { var u = userService.getUser(); function callback(datum, status, headers, config) { if (datum == null) { $scope.username_password_error = 'error communicating with server.'; } else { if (datum.jrStatus == "Ok") { $scope.change_password_error = 'Password Changed.'; // FIXME -- I18N $scope.password = emptyPassword(); } else { $scope.change_password_error = datum.jrData; } } }; if (u.isAuthenticated) { $http. post(url, $scope.password). success(callback). error(callback); } else { $scope.change_password_error = 'Not Authenticated.'; // FIXME -- I18N } }; // requestResetPassword() requestResetEmpty = function () { return { rrpUsername: '' }; }; $scope.requestReset = requestResetEmpty(); $scope.requestResetPassword = function () { function callback(datum, status, headers, config) { if (datum == null) { $scope.request_reset_password_msg = 'error communicating with the server.'; } else { if (datum.jrStatus == "Ok") { $scope.request_reset_password_msg = datum.jrData; $scope.requestReset = requestResetEmpty(); } else { $scope.request_reset_password_msg = datum.jrData; } } } $http.post(`(showURL PasswordRequestReset [])`, $scope.requestReset). success(callback). error(callback); }; // resetPassword() resetEmpty = function () { return { rpPassword: '', rpPasswordConfirm: '' }; }; $scope.reset = resetEmpty(); $scope.resetPassword = function () { function callback(datum, status, headers, config) { if (datum == null) { $scope.reset_password_msg = 'error communicating with the server.'; } else { if (datum.jrStatus == "Ok") { $scope.reset_password_msg = datum.jrData; $scope.reset = resetEmpty(); } else { $scope.reset_password_msg = datum.jrData; } } } var resetToken = $location.search().reset_token; if (resetToken) { $scope.reset.rpResetToken = resetToken; $http.post(`(showURL PasswordReset [])`, $scope.reset). success(callback). error(callback); } else { $scope.reset_password_msg = "reset token not found."; // FIXME -- I18N } }; }]); /* usernamePassword.factory('authInterceptor', ['$rootScope', '$q', '$window', 'userService', function ($rootScope, $q, $window, userService) { return { request: function (config) { config.headers = config.headers || {}; u = userService.getUser(); if (u && u.token) { config.headers.Authorization = 'Bearer ' + u.token; } return config; }, responseError: function (rejection) { if (rejection.status === 401) { // handle the case where the user is not authenticated userService.clearUser(); document.cookie = 'atc=; path=/; expires=Thu, 01-Jan-70 00:00:01 GMT;'; } return $q.reject(rejection); } }; }]); usernamePassword.config(['$httpProvider', function ($httpProvider) { $httpProvider.interceptors.push('authInterceptor'); }]); */ // upAuthenticated directive usernamePassword.directive('upAuthenticated', ['$rootScope', 'userService', function ($rootScope, userService) { return { restrict: 'A', link: function (scope, element, attrs) { var prevDisp = element.css('display'); $rootScope.$watch(function () { return userService.getUser().isAuthenticated; }, function(auth) { if (auth != (attrs.upAuthenticated == 'true')) { element.css('display', 'none'); } else { element.css('display', prevDisp); } }); } }; }]); // upLogout directive usernamePassword.directive('upLogout', ['$rootScope', 'userService', function ($rootScope, userService) { return { restrict: 'E', replace: true, templateUrl: `(showURL (Partial Logout) [])` }; }]); // upLogin directive usernamePassword.directive('upLogin', ['$rootScope', 'userService', function ($rootScope, userService) { return { restrict: 'E', replace: true, templateUrl: `(showURL (Partial Login) [])` }; }]); // upLoginInline directive usernamePassword.directive('upLoginInline', ['$rootScope', 'userService', function ($rootScope, userService) { return { restrict: 'E', replace: true, templateUrl: `(showURL (Partial LoginInline) [])` }; }]); // upChangePassword directive usernamePassword.directive('upChangePassword', ['$rootScope', '$http', '$compile', 'userService', function ($rootScope, $http, $compile, userService) { function link(scope, element, attrs) { $rootScope.$watch(function() { return userService.getUser().isAuthenticated; }, function(auth) { if (auth == true) { $http.get(`(showURL (Partial ChangePassword) [])`). success(function(datum, status, headers, config) { element.empty(); var newElem = angular.element(datum); element.append(newElem); $compile(newElem)(scope); }); } else { element.empty(); } }); } return { restrict: 'E', link: link }; }]); // upRequestResetPassword directive usernamePassword.directive('upRequestResetPassword', [function () { return { restrict: 'E', templateUrl: `(showURL (Partial RequestResetPasswordForm) [])` }; }]); // upResetPassword directive usernamePassword.directive('upResetPassword', [function () { return { restrict: 'E', templateUrl: `(showURL (Partial ResetPasswordForm) [])` }; }]); // upSignupPassword directive usernamePassword.directive('upSignupPassword', [function () { return { restrict: 'E', templateUrl: `(showURL (Partial SignupPassword) [])` }; }]); } |] where loginRedirect :: Maybe a -> JStat loginRedirect (Just a plr) = [jmacro| // console.log(`"loginRedirect - " ++ show plr`); window.location.href = `plr`; |] loginRedirect Maybe a Nothing = [JStat] -> JStat BlockStat []