6
6
permission . run ( [ '$rootScope' , 'Permission' , '$state' , '$q' , function ( $rootScope , Permission , $state , $q ) {
7
7
$rootScope . $on ( '$stateChangeStart' , function ( event , toState , toParams , fromState , fromParams ) {
8
8
9
- if ( toState . $$finishAuthorize || ! toState . data || ! toState . data . permissions ) {
10
- return ;
9
+ if ( areSetStatePermissions ( ) ) {
10
+ setStateAuthorizationStatus ( true ) ;
11
+ event . preventDefault ( ) ;
12
+
13
+ if ( ! areStateEventsDefaultPrevented ( ) ) {
14
+ var permissions = toState . data . permissions ;
15
+ authorizeForState ( permissions ) ;
16
+ }
17
+ } else {
18
+ setStateAuthorizationStatus ( false ) ;
19
+ }
20
+
21
+ /**
22
+ * Checks if state is qualified to be permission based verified
23
+ *
24
+ * @returns {boolean }
25
+ */
26
+ function areSetStatePermissions ( ) {
27
+ return ! toState . $$isAuthorizationFinished && toState . data && toState . data . permissions ;
11
28
}
12
29
13
- var permissions = toState . data . permissions ;
30
+ /**
31
+ * Sets internal state `$$finishedAuthorization` variable to prevent looping
32
+ *
33
+ * @param status {boolean} When true authorization has been already preceded
34
+ */
35
+ function setStateAuthorizationStatus ( status ) {
36
+ toState = angular . extend ( { '$$isAuthorizationFinished' : status } , toState ) ;
37
+ }
14
38
15
- event . preventDefault ( ) ;
16
- toState = angular . extend ( { '$$finishAuthorize' : true } , toState ) ;
17
39
18
- if ( $rootScope . $broadcast ( '$stateChangePermissionStart' , toState , toParams ) . defaultPrevented ) {
19
- return ;
40
+ /**
41
+ * Checks if state events are not prevented by default
42
+ *
43
+ * @returns {boolean }
44
+ */
45
+ function areStateEventsDefaultPrevented ( ) {
46
+ return isStateChangePermissionStartDefaultPrevented ( ) || isStateChangeStartDefaultPrevented ( ) ;
20
47
}
21
48
22
- Permission
23
- . authorize ( permissions , toParams )
24
- . then ( function ( ) {
25
- // If authorized, use call state.go without triggering the event.
26
- // Then trigger $stateChangeSuccess manually to resume the rest of the process
27
- // Note: This is a pseudo-hacky fix which should be fixed in future ui-router versions
28
- if ( ! $rootScope . $broadcast ( '$stateChangeStart' , toState , toParams , fromState , fromParams ) . defaultPrevented ) {
49
+ /**
50
+ * Handles state authorization
51
+ *
52
+ * @param permissions {Object} Map of "only" or "except" permission names
53
+ */
54
+ function authorizeForState ( permissions ) {
55
+ Permission
56
+ . authorize ( permissions , toParams )
57
+ . then ( function ( ) {
29
58
$rootScope . $broadcast ( '$stateChangePermissionAccepted' , toState , toParams ) ;
30
-
31
- $state
32
- . go ( toState . name , toParams , { notify : false } )
33
- . then ( function ( ) {
34
- $rootScope
35
- . $broadcast ( '$stateChangeSuccess' , toState , toParams , fromState , fromParams ) ;
36
- } ) ;
37
- }
38
- } )
39
- . catch ( function ( ) {
40
- if ( ! $rootScope . $broadcast ( '$stateChangeStart' , toState , toParams , fromState , fromParams ) . defaultPrevented ) {
59
+ goToState ( toState . name ) ;
60
+ } )
61
+ . catch ( function ( rejectedPermission ) {
41
62
$rootScope . $broadcast ( '$stateChangePermissionDenied' , toState , toParams ) ;
63
+ redirectToState ( permissions . redirectTo , rejectedPermission ) ;
64
+ } ) ;
65
+ }
42
66
43
- var redirectTo = permissions . redirectTo ;
67
+ /**
68
+ * Redirects to states when permissions are met
69
+ *
70
+ * If authorized, use call state.go without triggering the event.
71
+ * Then trigger $stateChangeSuccess manually to resume the rest of the process
72
+ * Note: This is a pseudo-hacky fix which should be fixed in future ui-router versions
73
+ */
74
+ function goToState ( name ) {
75
+ $state
76
+ . go ( name , toParams , { notify : false } )
77
+ . then ( function ( ) {
78
+ $rootScope
79
+ . $broadcast ( '$stateChangeSuccess' , toState , toParams , fromState , fromParams ) ;
80
+ } ) ;
81
+ }
82
+
83
+ /**
84
+ * Redirects to fallback states when permissions fail
85
+ *
86
+ * @param redirectTo {Object|Function|String} Redirection configuration
87
+ * @param permission {String} Permission name
88
+ */
89
+ function redirectToState ( redirectTo , permission ) {
90
+ if ( angular . isFunction ( redirectTo ) ) {
91
+ handleFunctionRedirect ( redirectTo , permission ) ;
92
+ }
44
93
45
- if ( angular . isFunction ( redirectTo ) ) {
46
- redirectTo = redirectTo ( ) ;
94
+ if ( angular . isObject ( redirectTo ) ) {
95
+ handleObjectRedirect ( redirectTo , permission ) ;
96
+ }
47
97
48
- $q . when ( redirectTo ) . then ( function ( newState ) {
49
- if ( newState ) {
50
- $state . go ( newState , toParams ) ;
51
- }
52
- } ) ;
98
+ if ( angular . isString ( redirectTo ) ) {
99
+ handleStringRedirect ( redirectTo ) ;
100
+ }
101
+ }
53
102
54
- } else {
55
- if ( redirectTo ) {
56
- $state . go ( redirectTo , toParams ) ;
57
- }
103
+ /**
104
+ * Handles function based redirection for rejected permissions
105
+ *
106
+ * @param redirectFunction {Function} Redirection function
107
+ * @param permission {String} Rejected permission
108
+ */
109
+ function handleFunctionRedirect ( redirectFunction , permission ) {
110
+ $q . when ( redirectFunction . call ( null , permission ) )
111
+ . then ( function ( redirectState ) {
112
+ if ( ! angular . isString ( redirectState ) ) {
113
+ throw new TypeError ( 'When used "redirectTo" as function, returned value must be string with state name' ) ;
58
114
}
59
- }
60
- } ) ;
115
+ handleStringRedirect ( redirectState ) ;
116
+ } ) ;
117
+ }
118
+
119
+ /**
120
+ * Handles object based redirection for rejected permissions
121
+ *
122
+ * @param redirectObject {Object} Redirection function
123
+ * @param permission {String} Rejected permission
124
+ */
125
+ function handleObjectRedirect ( redirectObject , permission ) {
126
+ if ( ! angular . isDefined ( redirectObject [ 'default' ] ) ) {
127
+ throw new ReferenceError ( 'When used "redirectTo" as object, property "default" must be defined' ) ;
128
+ }
129
+
130
+ var redirectState = redirectObject [ permission ] ;
131
+
132
+ if ( ! angular . isDefined ( redirectState ) ) {
133
+ redirectState = redirectObject [ 'default' ] ;
134
+ }
135
+
136
+ if ( angular . isFunction ( redirectState ) ) {
137
+ handleFunctionRedirect ( redirectState , permission ) ;
138
+ }
139
+
140
+ if ( angular . isString ( redirectState ) ) {
141
+ handleStringRedirect ( redirectState ) ;
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Handles string based redirection for rejected permissions
147
+ *
148
+ * @param state {String} State to which app should be redirected
149
+ */
150
+ function handleStringRedirect ( state ) {
151
+ $state . go ( state , toParams ) ;
152
+ }
153
+
154
+ /**
155
+ * Checks if event $stateChangeStart hasn't been disabled by default
156
+ *
157
+ * @returns {boolean }
158
+ */
159
+ function isStateChangeStartDefaultPrevented ( ) {
160
+ return $rootScope . $broadcast ( '$stateChangeStart' , toState , toParams , fromState , fromParams ) . defaultPrevented ;
161
+ }
162
+
163
+ /**
164
+ * Checks if event $stateChangePermissionStart hasn't been disabled by default
165
+ *
166
+ * @returns {boolean }
167
+ */
168
+ function isStateChangePermissionStartDefaultPrevented ( ) {
169
+ return $rootScope . $broadcast ( '$stateChangePermissionStart' , toState , toParams ) . defaultPrevented ;
170
+ }
61
171
} ) ;
62
172
} ] ) ;
63
- } ( ) ) ;
173
+ } ( ) ) ;
0 commit comments