strapi-plugin-keycloak-realm-users 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +485 -0
- package/__tests__/constants.test.mjs +207 -0
- package/__tests__/mocks/strapi.mjs +182 -0
- package/__tests__/services/audit-log.test.mjs +283 -0
- package/__tests__/services/keycloak-client.test.mjs +651 -0
- package/__tests__/services/permission.test.mjs +374 -0
- package/__tests__/services/realm.test.mjs +415 -0
- package/__tests__/services/user.test.mjs +487 -0
- package/__tests__/utils/errors.test.mjs +109 -0
- package/admin/src/components/Initializer.jsx +14 -0
- package/admin/src/components/RealmBadge.jsx +17 -0
- package/admin/src/constants.js +14 -0
- package/admin/src/hooks/useAuditLogs.js +142 -0
- package/admin/src/hooks/useKeycloakRoles.js +182 -0
- package/admin/src/hooks/useKeycloakUsers.js +477 -0
- package/admin/src/hooks/useRealmAdmins.js +249 -0
- package/admin/src/hooks/useRealms.js +269 -0
- package/admin/src/index.js +46 -0
- package/admin/src/pages/App.jsx +21 -0
- package/admin/src/pages/AuditPage/index.jsx +213 -0
- package/admin/src/pages/RealmsPage/RealmEditPage.jsx +791 -0
- package/admin/src/pages/RealmsPage/RealmListPage.jsx +231 -0
- package/admin/src/pages/RealmsPage/index.jsx +7 -0
- package/admin/src/pages/UsersPage/UserEditPage.jsx +313 -0
- package/admin/src/pages/UsersPage/UserListPage.jsx +437 -0
- package/admin/src/pages/UsersPage/index.jsx +7 -0
- package/admin/src/pluginId.js +2 -0
- package/admin/src/translations/en.json +77 -0
- package/admin/src/translations/fr.json +77 -0
- package/babel.config.cjs +17 -0
- package/coverage/clover.xml +422 -0
- package/coverage/coverage-final.json +8 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +146 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/bootstrap.js.html +346 -0
- package/coverage/lcov-report/src/config/index.html +116 -0
- package/coverage/lcov-report/src/config/index.js.html +106 -0
- package/coverage/lcov-report/src/constants.js.html +850 -0
- package/coverage/lcov-report/src/content-types/audit-log/index.html +116 -0
- package/coverage/lcov-report/src/content-types/audit-log/index.js.html +94 -0
- package/coverage/lcov-report/src/content-types/index.html +116 -0
- package/coverage/lcov-report/src/content-types/index.js.html +112 -0
- package/coverage/lcov-report/src/content-types/realm-admin/index.html +116 -0
- package/coverage/lcov-report/src/content-types/realm-admin/index.js.html +94 -0
- package/coverage/lcov-report/src/content-types/realm-config/index.html +116 -0
- package/coverage/lcov-report/src/content-types/realm-config/index.js.html +94 -0
- package/coverage/lcov-report/src/controllers/audit.js.html +517 -0
- package/coverage/lcov-report/src/controllers/index.html +161 -0
- package/coverage/lcov-report/src/controllers/index.js.html +112 -0
- package/coverage/lcov-report/src/controllers/realm.js.html +1057 -0
- package/coverage/lcov-report/src/controllers/user.js.html +1324 -0
- package/coverage/lcov-report/src/destroy.js.html +100 -0
- package/coverage/lcov-report/src/index.html +116 -0
- package/coverage/lcov-report/src/policies/can-access-realm.js.html +163 -0
- package/coverage/lcov-report/src/policies/index.html +146 -0
- package/coverage/lcov-report/src/policies/index.js.html +106 -0
- package/coverage/lcov-report/src/policies/is-authenticated.js.html +100 -0
- package/coverage/lcov-report/src/register.js.html +106 -0
- package/coverage/lcov-report/src/routes/admin.js.html +844 -0
- package/coverage/lcov-report/src/routes/index.html +131 -0
- package/coverage/lcov-report/src/routes/index.js.html +109 -0
- package/coverage/lcov-report/src/services/audit-log.js.html +673 -0
- package/coverage/lcov-report/src/services/index.html +176 -0
- package/coverage/lcov-report/src/services/index.js.html +124 -0
- package/coverage/lcov-report/src/services/keycloak-client.js.html +2359 -0
- package/coverage/lcov-report/src/services/permission.js.html +955 -0
- package/coverage/lcov-report/src/services/realm.js.html +1207 -0
- package/coverage/lcov-report/src/services/user.js.html +1924 -0
- package/coverage/lcov-report/src/utils/errors.js.html +274 -0
- package/coverage/lcov-report/src/utils/index.html +116 -0
- package/coverage/lcov-report/src/utils/index.js.html +103 -0
- package/coverage/lcov.info +804 -0
- package/dist/_chunks/App-BaKrvCeS.mjs +1975 -0
- package/dist/_chunks/App-DO6syS77.js +1975 -0
- package/dist/_chunks/en-Li-XBDe9.mjs +72 -0
- package/dist/_chunks/en-aCyfgNfr.js +72 -0
- package/dist/_chunks/fr-Cj33Q8jI.js +72 -0
- package/dist/_chunks/fr-vLrXph-Z.mjs +72 -0
- package/dist/_chunks/index-DwDO4-0C.js +69 -0
- package/dist/_chunks/index-jTVd7LdQ.mjs +70 -0
- package/dist/admin/index.js +3 -0
- package/dist/admin/index.mjs +4 -0
- package/dist/server/index.js +3003 -0
- package/dist/server/index.mjs +3004 -0
- package/jest.config.cjs +50 -0
- package/package.json +55 -0
- package/server/src/bootstrap.js +87 -0
- package/server/src/config/index.js +7 -0
- package/server/src/constants.js +255 -0
- package/server/src/content-types/audit-log/index.js +3 -0
- package/server/src/content-types/audit-log/schema.json +61 -0
- package/server/src/content-types/index.js +9 -0
- package/server/src/content-types/realm-admin/index.js +3 -0
- package/server/src/content-types/realm-admin/schema.json +45 -0
- package/server/src/content-types/realm-config/index.js +3 -0
- package/server/src/content-types/realm-config/schema.json +56 -0
- package/server/src/controllers/audit.js +144 -0
- package/server/src/controllers/index.js +9 -0
- package/server/src/controllers/realm.js +324 -0
- package/server/src/controllers/user.js +413 -0
- package/server/src/destroy.js +5 -0
- package/server/src/index.js +21 -0
- package/server/src/policies/can-access-realm.js +26 -0
- package/server/src/policies/index.js +7 -0
- package/server/src/policies/is-authenticated.js +5 -0
- package/server/src/register.js +7 -0
- package/server/src/routes/admin.js +253 -0
- package/server/src/routes/index.js +8 -0
- package/server/src/services/audit-log.js +196 -0
- package/server/src/services/index.js +13 -0
- package/server/src/services/keycloak-client.js +758 -0
- package/server/src/services/permission.js +290 -0
- package/server/src/services/realm.js +374 -0
- package/server/src/services/user.js +613 -0
- package/server/src/utils/errors.js +63 -0
- package/server/src/utils/index.js +6 -0
|
@@ -0,0 +1,1207 @@
|
|
|
1
|
+
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
|
|
5
|
+
<head>
|
|
6
|
+
<title>Code coverage report for src/services/realm.js</title>
|
|
7
|
+
<meta charset="utf-8" />
|
|
8
|
+
<link rel="stylesheet" href="../../prettify.css" />
|
|
9
|
+
<link rel="stylesheet" href="../../base.css" />
|
|
10
|
+
<link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
|
|
11
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
12
|
+
<style type='text/css'>
|
|
13
|
+
.coverage-summary .sorter {
|
|
14
|
+
background-image: url(../../sort-arrow-sprite.png);
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
|
|
19
|
+
<body>
|
|
20
|
+
<div class='wrapper'>
|
|
21
|
+
<div class='pad1'>
|
|
22
|
+
<h1><a href="../../index.html">All files</a> / <a href="index.html">src/services</a> realm.js</h1>
|
|
23
|
+
<div class='clearfix'>
|
|
24
|
+
|
|
25
|
+
<div class='fl pad1y space-right2'>
|
|
26
|
+
<span class="strong">100% </span>
|
|
27
|
+
<span class="quiet">Statements</span>
|
|
28
|
+
<span class='fraction'>52/52</span>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<div class='fl pad1y space-right2'>
|
|
33
|
+
<span class="strong">97.56% </span>
|
|
34
|
+
<span class="quiet">Branches</span>
|
|
35
|
+
<span class='fraction'>40/41</span>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
<div class='fl pad1y space-right2'>
|
|
40
|
+
<span class="strong">100% </span>
|
|
41
|
+
<span class="quiet">Functions</span>
|
|
42
|
+
<span class='fraction'>13/13</span>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<div class='fl pad1y space-right2'>
|
|
47
|
+
<span class="strong">100% </span>
|
|
48
|
+
<span class="quiet">Lines</span>
|
|
49
|
+
<span class='fraction'>51/51</span>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
<p class="quiet">
|
|
55
|
+
Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
|
|
56
|
+
</p>
|
|
57
|
+
<template id="filterTemplate">
|
|
58
|
+
<div class="quiet">
|
|
59
|
+
Filter:
|
|
60
|
+
<input type="search" id="fileSearch">
|
|
61
|
+
</div>
|
|
62
|
+
</template>
|
|
63
|
+
</div>
|
|
64
|
+
<div class='status-line high'></div>
|
|
65
|
+
<pre><table class="coverage">
|
|
66
|
+
<tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
|
|
67
|
+
<a name='L2'></a><a href='#L2'>2</a>
|
|
68
|
+
<a name='L3'></a><a href='#L3'>3</a>
|
|
69
|
+
<a name='L4'></a><a href='#L4'>4</a>
|
|
70
|
+
<a name='L5'></a><a href='#L5'>5</a>
|
|
71
|
+
<a name='L6'></a><a href='#L6'>6</a>
|
|
72
|
+
<a name='L7'></a><a href='#L7'>7</a>
|
|
73
|
+
<a name='L8'></a><a href='#L8'>8</a>
|
|
74
|
+
<a name='L9'></a><a href='#L9'>9</a>
|
|
75
|
+
<a name='L10'></a><a href='#L10'>10</a>
|
|
76
|
+
<a name='L11'></a><a href='#L11'>11</a>
|
|
77
|
+
<a name='L12'></a><a href='#L12'>12</a>
|
|
78
|
+
<a name='L13'></a><a href='#L13'>13</a>
|
|
79
|
+
<a name='L14'></a><a href='#L14'>14</a>
|
|
80
|
+
<a name='L15'></a><a href='#L15'>15</a>
|
|
81
|
+
<a name='L16'></a><a href='#L16'>16</a>
|
|
82
|
+
<a name='L17'></a><a href='#L17'>17</a>
|
|
83
|
+
<a name='L18'></a><a href='#L18'>18</a>
|
|
84
|
+
<a name='L19'></a><a href='#L19'>19</a>
|
|
85
|
+
<a name='L20'></a><a href='#L20'>20</a>
|
|
86
|
+
<a name='L21'></a><a href='#L21'>21</a>
|
|
87
|
+
<a name='L22'></a><a href='#L22'>22</a>
|
|
88
|
+
<a name='L23'></a><a href='#L23'>23</a>
|
|
89
|
+
<a name='L24'></a><a href='#L24'>24</a>
|
|
90
|
+
<a name='L25'></a><a href='#L25'>25</a>
|
|
91
|
+
<a name='L26'></a><a href='#L26'>26</a>
|
|
92
|
+
<a name='L27'></a><a href='#L27'>27</a>
|
|
93
|
+
<a name='L28'></a><a href='#L28'>28</a>
|
|
94
|
+
<a name='L29'></a><a href='#L29'>29</a>
|
|
95
|
+
<a name='L30'></a><a href='#L30'>30</a>
|
|
96
|
+
<a name='L31'></a><a href='#L31'>31</a>
|
|
97
|
+
<a name='L32'></a><a href='#L32'>32</a>
|
|
98
|
+
<a name='L33'></a><a href='#L33'>33</a>
|
|
99
|
+
<a name='L34'></a><a href='#L34'>34</a>
|
|
100
|
+
<a name='L35'></a><a href='#L35'>35</a>
|
|
101
|
+
<a name='L36'></a><a href='#L36'>36</a>
|
|
102
|
+
<a name='L37'></a><a href='#L37'>37</a>
|
|
103
|
+
<a name='L38'></a><a href='#L38'>38</a>
|
|
104
|
+
<a name='L39'></a><a href='#L39'>39</a>
|
|
105
|
+
<a name='L40'></a><a href='#L40'>40</a>
|
|
106
|
+
<a name='L41'></a><a href='#L41'>41</a>
|
|
107
|
+
<a name='L42'></a><a href='#L42'>42</a>
|
|
108
|
+
<a name='L43'></a><a href='#L43'>43</a>
|
|
109
|
+
<a name='L44'></a><a href='#L44'>44</a>
|
|
110
|
+
<a name='L45'></a><a href='#L45'>45</a>
|
|
111
|
+
<a name='L46'></a><a href='#L46'>46</a>
|
|
112
|
+
<a name='L47'></a><a href='#L47'>47</a>
|
|
113
|
+
<a name='L48'></a><a href='#L48'>48</a>
|
|
114
|
+
<a name='L49'></a><a href='#L49'>49</a>
|
|
115
|
+
<a name='L50'></a><a href='#L50'>50</a>
|
|
116
|
+
<a name='L51'></a><a href='#L51'>51</a>
|
|
117
|
+
<a name='L52'></a><a href='#L52'>52</a>
|
|
118
|
+
<a name='L53'></a><a href='#L53'>53</a>
|
|
119
|
+
<a name='L54'></a><a href='#L54'>54</a>
|
|
120
|
+
<a name='L55'></a><a href='#L55'>55</a>
|
|
121
|
+
<a name='L56'></a><a href='#L56'>56</a>
|
|
122
|
+
<a name='L57'></a><a href='#L57'>57</a>
|
|
123
|
+
<a name='L58'></a><a href='#L58'>58</a>
|
|
124
|
+
<a name='L59'></a><a href='#L59'>59</a>
|
|
125
|
+
<a name='L60'></a><a href='#L60'>60</a>
|
|
126
|
+
<a name='L61'></a><a href='#L61'>61</a>
|
|
127
|
+
<a name='L62'></a><a href='#L62'>62</a>
|
|
128
|
+
<a name='L63'></a><a href='#L63'>63</a>
|
|
129
|
+
<a name='L64'></a><a href='#L64'>64</a>
|
|
130
|
+
<a name='L65'></a><a href='#L65'>65</a>
|
|
131
|
+
<a name='L66'></a><a href='#L66'>66</a>
|
|
132
|
+
<a name='L67'></a><a href='#L67'>67</a>
|
|
133
|
+
<a name='L68'></a><a href='#L68'>68</a>
|
|
134
|
+
<a name='L69'></a><a href='#L69'>69</a>
|
|
135
|
+
<a name='L70'></a><a href='#L70'>70</a>
|
|
136
|
+
<a name='L71'></a><a href='#L71'>71</a>
|
|
137
|
+
<a name='L72'></a><a href='#L72'>72</a>
|
|
138
|
+
<a name='L73'></a><a href='#L73'>73</a>
|
|
139
|
+
<a name='L74'></a><a href='#L74'>74</a>
|
|
140
|
+
<a name='L75'></a><a href='#L75'>75</a>
|
|
141
|
+
<a name='L76'></a><a href='#L76'>76</a>
|
|
142
|
+
<a name='L77'></a><a href='#L77'>77</a>
|
|
143
|
+
<a name='L78'></a><a href='#L78'>78</a>
|
|
144
|
+
<a name='L79'></a><a href='#L79'>79</a>
|
|
145
|
+
<a name='L80'></a><a href='#L80'>80</a>
|
|
146
|
+
<a name='L81'></a><a href='#L81'>81</a>
|
|
147
|
+
<a name='L82'></a><a href='#L82'>82</a>
|
|
148
|
+
<a name='L83'></a><a href='#L83'>83</a>
|
|
149
|
+
<a name='L84'></a><a href='#L84'>84</a>
|
|
150
|
+
<a name='L85'></a><a href='#L85'>85</a>
|
|
151
|
+
<a name='L86'></a><a href='#L86'>86</a>
|
|
152
|
+
<a name='L87'></a><a href='#L87'>87</a>
|
|
153
|
+
<a name='L88'></a><a href='#L88'>88</a>
|
|
154
|
+
<a name='L89'></a><a href='#L89'>89</a>
|
|
155
|
+
<a name='L90'></a><a href='#L90'>90</a>
|
|
156
|
+
<a name='L91'></a><a href='#L91'>91</a>
|
|
157
|
+
<a name='L92'></a><a href='#L92'>92</a>
|
|
158
|
+
<a name='L93'></a><a href='#L93'>93</a>
|
|
159
|
+
<a name='L94'></a><a href='#L94'>94</a>
|
|
160
|
+
<a name='L95'></a><a href='#L95'>95</a>
|
|
161
|
+
<a name='L96'></a><a href='#L96'>96</a>
|
|
162
|
+
<a name='L97'></a><a href='#L97'>97</a>
|
|
163
|
+
<a name='L98'></a><a href='#L98'>98</a>
|
|
164
|
+
<a name='L99'></a><a href='#L99'>99</a>
|
|
165
|
+
<a name='L100'></a><a href='#L100'>100</a>
|
|
166
|
+
<a name='L101'></a><a href='#L101'>101</a>
|
|
167
|
+
<a name='L102'></a><a href='#L102'>102</a>
|
|
168
|
+
<a name='L103'></a><a href='#L103'>103</a>
|
|
169
|
+
<a name='L104'></a><a href='#L104'>104</a>
|
|
170
|
+
<a name='L105'></a><a href='#L105'>105</a>
|
|
171
|
+
<a name='L106'></a><a href='#L106'>106</a>
|
|
172
|
+
<a name='L107'></a><a href='#L107'>107</a>
|
|
173
|
+
<a name='L108'></a><a href='#L108'>108</a>
|
|
174
|
+
<a name='L109'></a><a href='#L109'>109</a>
|
|
175
|
+
<a name='L110'></a><a href='#L110'>110</a>
|
|
176
|
+
<a name='L111'></a><a href='#L111'>111</a>
|
|
177
|
+
<a name='L112'></a><a href='#L112'>112</a>
|
|
178
|
+
<a name='L113'></a><a href='#L113'>113</a>
|
|
179
|
+
<a name='L114'></a><a href='#L114'>114</a>
|
|
180
|
+
<a name='L115'></a><a href='#L115'>115</a>
|
|
181
|
+
<a name='L116'></a><a href='#L116'>116</a>
|
|
182
|
+
<a name='L117'></a><a href='#L117'>117</a>
|
|
183
|
+
<a name='L118'></a><a href='#L118'>118</a>
|
|
184
|
+
<a name='L119'></a><a href='#L119'>119</a>
|
|
185
|
+
<a name='L120'></a><a href='#L120'>120</a>
|
|
186
|
+
<a name='L121'></a><a href='#L121'>121</a>
|
|
187
|
+
<a name='L122'></a><a href='#L122'>122</a>
|
|
188
|
+
<a name='L123'></a><a href='#L123'>123</a>
|
|
189
|
+
<a name='L124'></a><a href='#L124'>124</a>
|
|
190
|
+
<a name='L125'></a><a href='#L125'>125</a>
|
|
191
|
+
<a name='L126'></a><a href='#L126'>126</a>
|
|
192
|
+
<a name='L127'></a><a href='#L127'>127</a>
|
|
193
|
+
<a name='L128'></a><a href='#L128'>128</a>
|
|
194
|
+
<a name='L129'></a><a href='#L129'>129</a>
|
|
195
|
+
<a name='L130'></a><a href='#L130'>130</a>
|
|
196
|
+
<a name='L131'></a><a href='#L131'>131</a>
|
|
197
|
+
<a name='L132'></a><a href='#L132'>132</a>
|
|
198
|
+
<a name='L133'></a><a href='#L133'>133</a>
|
|
199
|
+
<a name='L134'></a><a href='#L134'>134</a>
|
|
200
|
+
<a name='L135'></a><a href='#L135'>135</a>
|
|
201
|
+
<a name='L136'></a><a href='#L136'>136</a>
|
|
202
|
+
<a name='L137'></a><a href='#L137'>137</a>
|
|
203
|
+
<a name='L138'></a><a href='#L138'>138</a>
|
|
204
|
+
<a name='L139'></a><a href='#L139'>139</a>
|
|
205
|
+
<a name='L140'></a><a href='#L140'>140</a>
|
|
206
|
+
<a name='L141'></a><a href='#L141'>141</a>
|
|
207
|
+
<a name='L142'></a><a href='#L142'>142</a>
|
|
208
|
+
<a name='L143'></a><a href='#L143'>143</a>
|
|
209
|
+
<a name='L144'></a><a href='#L144'>144</a>
|
|
210
|
+
<a name='L145'></a><a href='#L145'>145</a>
|
|
211
|
+
<a name='L146'></a><a href='#L146'>146</a>
|
|
212
|
+
<a name='L147'></a><a href='#L147'>147</a>
|
|
213
|
+
<a name='L148'></a><a href='#L148'>148</a>
|
|
214
|
+
<a name='L149'></a><a href='#L149'>149</a>
|
|
215
|
+
<a name='L150'></a><a href='#L150'>150</a>
|
|
216
|
+
<a name='L151'></a><a href='#L151'>151</a>
|
|
217
|
+
<a name='L152'></a><a href='#L152'>152</a>
|
|
218
|
+
<a name='L153'></a><a href='#L153'>153</a>
|
|
219
|
+
<a name='L154'></a><a href='#L154'>154</a>
|
|
220
|
+
<a name='L155'></a><a href='#L155'>155</a>
|
|
221
|
+
<a name='L156'></a><a href='#L156'>156</a>
|
|
222
|
+
<a name='L157'></a><a href='#L157'>157</a>
|
|
223
|
+
<a name='L158'></a><a href='#L158'>158</a>
|
|
224
|
+
<a name='L159'></a><a href='#L159'>159</a>
|
|
225
|
+
<a name='L160'></a><a href='#L160'>160</a>
|
|
226
|
+
<a name='L161'></a><a href='#L161'>161</a>
|
|
227
|
+
<a name='L162'></a><a href='#L162'>162</a>
|
|
228
|
+
<a name='L163'></a><a href='#L163'>163</a>
|
|
229
|
+
<a name='L164'></a><a href='#L164'>164</a>
|
|
230
|
+
<a name='L165'></a><a href='#L165'>165</a>
|
|
231
|
+
<a name='L166'></a><a href='#L166'>166</a>
|
|
232
|
+
<a name='L167'></a><a href='#L167'>167</a>
|
|
233
|
+
<a name='L168'></a><a href='#L168'>168</a>
|
|
234
|
+
<a name='L169'></a><a href='#L169'>169</a>
|
|
235
|
+
<a name='L170'></a><a href='#L170'>170</a>
|
|
236
|
+
<a name='L171'></a><a href='#L171'>171</a>
|
|
237
|
+
<a name='L172'></a><a href='#L172'>172</a>
|
|
238
|
+
<a name='L173'></a><a href='#L173'>173</a>
|
|
239
|
+
<a name='L174'></a><a href='#L174'>174</a>
|
|
240
|
+
<a name='L175'></a><a href='#L175'>175</a>
|
|
241
|
+
<a name='L176'></a><a href='#L176'>176</a>
|
|
242
|
+
<a name='L177'></a><a href='#L177'>177</a>
|
|
243
|
+
<a name='L178'></a><a href='#L178'>178</a>
|
|
244
|
+
<a name='L179'></a><a href='#L179'>179</a>
|
|
245
|
+
<a name='L180'></a><a href='#L180'>180</a>
|
|
246
|
+
<a name='L181'></a><a href='#L181'>181</a>
|
|
247
|
+
<a name='L182'></a><a href='#L182'>182</a>
|
|
248
|
+
<a name='L183'></a><a href='#L183'>183</a>
|
|
249
|
+
<a name='L184'></a><a href='#L184'>184</a>
|
|
250
|
+
<a name='L185'></a><a href='#L185'>185</a>
|
|
251
|
+
<a name='L186'></a><a href='#L186'>186</a>
|
|
252
|
+
<a name='L187'></a><a href='#L187'>187</a>
|
|
253
|
+
<a name='L188'></a><a href='#L188'>188</a>
|
|
254
|
+
<a name='L189'></a><a href='#L189'>189</a>
|
|
255
|
+
<a name='L190'></a><a href='#L190'>190</a>
|
|
256
|
+
<a name='L191'></a><a href='#L191'>191</a>
|
|
257
|
+
<a name='L192'></a><a href='#L192'>192</a>
|
|
258
|
+
<a name='L193'></a><a href='#L193'>193</a>
|
|
259
|
+
<a name='L194'></a><a href='#L194'>194</a>
|
|
260
|
+
<a name='L195'></a><a href='#L195'>195</a>
|
|
261
|
+
<a name='L196'></a><a href='#L196'>196</a>
|
|
262
|
+
<a name='L197'></a><a href='#L197'>197</a>
|
|
263
|
+
<a name='L198'></a><a href='#L198'>198</a>
|
|
264
|
+
<a name='L199'></a><a href='#L199'>199</a>
|
|
265
|
+
<a name='L200'></a><a href='#L200'>200</a>
|
|
266
|
+
<a name='L201'></a><a href='#L201'>201</a>
|
|
267
|
+
<a name='L202'></a><a href='#L202'>202</a>
|
|
268
|
+
<a name='L203'></a><a href='#L203'>203</a>
|
|
269
|
+
<a name='L204'></a><a href='#L204'>204</a>
|
|
270
|
+
<a name='L205'></a><a href='#L205'>205</a>
|
|
271
|
+
<a name='L206'></a><a href='#L206'>206</a>
|
|
272
|
+
<a name='L207'></a><a href='#L207'>207</a>
|
|
273
|
+
<a name='L208'></a><a href='#L208'>208</a>
|
|
274
|
+
<a name='L209'></a><a href='#L209'>209</a>
|
|
275
|
+
<a name='L210'></a><a href='#L210'>210</a>
|
|
276
|
+
<a name='L211'></a><a href='#L211'>211</a>
|
|
277
|
+
<a name='L212'></a><a href='#L212'>212</a>
|
|
278
|
+
<a name='L213'></a><a href='#L213'>213</a>
|
|
279
|
+
<a name='L214'></a><a href='#L214'>214</a>
|
|
280
|
+
<a name='L215'></a><a href='#L215'>215</a>
|
|
281
|
+
<a name='L216'></a><a href='#L216'>216</a>
|
|
282
|
+
<a name='L217'></a><a href='#L217'>217</a>
|
|
283
|
+
<a name='L218'></a><a href='#L218'>218</a>
|
|
284
|
+
<a name='L219'></a><a href='#L219'>219</a>
|
|
285
|
+
<a name='L220'></a><a href='#L220'>220</a>
|
|
286
|
+
<a name='L221'></a><a href='#L221'>221</a>
|
|
287
|
+
<a name='L222'></a><a href='#L222'>222</a>
|
|
288
|
+
<a name='L223'></a><a href='#L223'>223</a>
|
|
289
|
+
<a name='L224'></a><a href='#L224'>224</a>
|
|
290
|
+
<a name='L225'></a><a href='#L225'>225</a>
|
|
291
|
+
<a name='L226'></a><a href='#L226'>226</a>
|
|
292
|
+
<a name='L227'></a><a href='#L227'>227</a>
|
|
293
|
+
<a name='L228'></a><a href='#L228'>228</a>
|
|
294
|
+
<a name='L229'></a><a href='#L229'>229</a>
|
|
295
|
+
<a name='L230'></a><a href='#L230'>230</a>
|
|
296
|
+
<a name='L231'></a><a href='#L231'>231</a>
|
|
297
|
+
<a name='L232'></a><a href='#L232'>232</a>
|
|
298
|
+
<a name='L233'></a><a href='#L233'>233</a>
|
|
299
|
+
<a name='L234'></a><a href='#L234'>234</a>
|
|
300
|
+
<a name='L235'></a><a href='#L235'>235</a>
|
|
301
|
+
<a name='L236'></a><a href='#L236'>236</a>
|
|
302
|
+
<a name='L237'></a><a href='#L237'>237</a>
|
|
303
|
+
<a name='L238'></a><a href='#L238'>238</a>
|
|
304
|
+
<a name='L239'></a><a href='#L239'>239</a>
|
|
305
|
+
<a name='L240'></a><a href='#L240'>240</a>
|
|
306
|
+
<a name='L241'></a><a href='#L241'>241</a>
|
|
307
|
+
<a name='L242'></a><a href='#L242'>242</a>
|
|
308
|
+
<a name='L243'></a><a href='#L243'>243</a>
|
|
309
|
+
<a name='L244'></a><a href='#L244'>244</a>
|
|
310
|
+
<a name='L245'></a><a href='#L245'>245</a>
|
|
311
|
+
<a name='L246'></a><a href='#L246'>246</a>
|
|
312
|
+
<a name='L247'></a><a href='#L247'>247</a>
|
|
313
|
+
<a name='L248'></a><a href='#L248'>248</a>
|
|
314
|
+
<a name='L249'></a><a href='#L249'>249</a>
|
|
315
|
+
<a name='L250'></a><a href='#L250'>250</a>
|
|
316
|
+
<a name='L251'></a><a href='#L251'>251</a>
|
|
317
|
+
<a name='L252'></a><a href='#L252'>252</a>
|
|
318
|
+
<a name='L253'></a><a href='#L253'>253</a>
|
|
319
|
+
<a name='L254'></a><a href='#L254'>254</a>
|
|
320
|
+
<a name='L255'></a><a href='#L255'>255</a>
|
|
321
|
+
<a name='L256'></a><a href='#L256'>256</a>
|
|
322
|
+
<a name='L257'></a><a href='#L257'>257</a>
|
|
323
|
+
<a name='L258'></a><a href='#L258'>258</a>
|
|
324
|
+
<a name='L259'></a><a href='#L259'>259</a>
|
|
325
|
+
<a name='L260'></a><a href='#L260'>260</a>
|
|
326
|
+
<a name='L261'></a><a href='#L261'>261</a>
|
|
327
|
+
<a name='L262'></a><a href='#L262'>262</a>
|
|
328
|
+
<a name='L263'></a><a href='#L263'>263</a>
|
|
329
|
+
<a name='L264'></a><a href='#L264'>264</a>
|
|
330
|
+
<a name='L265'></a><a href='#L265'>265</a>
|
|
331
|
+
<a name='L266'></a><a href='#L266'>266</a>
|
|
332
|
+
<a name='L267'></a><a href='#L267'>267</a>
|
|
333
|
+
<a name='L268'></a><a href='#L268'>268</a>
|
|
334
|
+
<a name='L269'></a><a href='#L269'>269</a>
|
|
335
|
+
<a name='L270'></a><a href='#L270'>270</a>
|
|
336
|
+
<a name='L271'></a><a href='#L271'>271</a>
|
|
337
|
+
<a name='L272'></a><a href='#L272'>272</a>
|
|
338
|
+
<a name='L273'></a><a href='#L273'>273</a>
|
|
339
|
+
<a name='L274'></a><a href='#L274'>274</a>
|
|
340
|
+
<a name='L275'></a><a href='#L275'>275</a>
|
|
341
|
+
<a name='L276'></a><a href='#L276'>276</a>
|
|
342
|
+
<a name='L277'></a><a href='#L277'>277</a>
|
|
343
|
+
<a name='L278'></a><a href='#L278'>278</a>
|
|
344
|
+
<a name='L279'></a><a href='#L279'>279</a>
|
|
345
|
+
<a name='L280'></a><a href='#L280'>280</a>
|
|
346
|
+
<a name='L281'></a><a href='#L281'>281</a>
|
|
347
|
+
<a name='L282'></a><a href='#L282'>282</a>
|
|
348
|
+
<a name='L283'></a><a href='#L283'>283</a>
|
|
349
|
+
<a name='L284'></a><a href='#L284'>284</a>
|
|
350
|
+
<a name='L285'></a><a href='#L285'>285</a>
|
|
351
|
+
<a name='L286'></a><a href='#L286'>286</a>
|
|
352
|
+
<a name='L287'></a><a href='#L287'>287</a>
|
|
353
|
+
<a name='L288'></a><a href='#L288'>288</a>
|
|
354
|
+
<a name='L289'></a><a href='#L289'>289</a>
|
|
355
|
+
<a name='L290'></a><a href='#L290'>290</a>
|
|
356
|
+
<a name='L291'></a><a href='#L291'>291</a>
|
|
357
|
+
<a name='L292'></a><a href='#L292'>292</a>
|
|
358
|
+
<a name='L293'></a><a href='#L293'>293</a>
|
|
359
|
+
<a name='L294'></a><a href='#L294'>294</a>
|
|
360
|
+
<a name='L295'></a><a href='#L295'>295</a>
|
|
361
|
+
<a name='L296'></a><a href='#L296'>296</a>
|
|
362
|
+
<a name='L297'></a><a href='#L297'>297</a>
|
|
363
|
+
<a name='L298'></a><a href='#L298'>298</a>
|
|
364
|
+
<a name='L299'></a><a href='#L299'>299</a>
|
|
365
|
+
<a name='L300'></a><a href='#L300'>300</a>
|
|
366
|
+
<a name='L301'></a><a href='#L301'>301</a>
|
|
367
|
+
<a name='L302'></a><a href='#L302'>302</a>
|
|
368
|
+
<a name='L303'></a><a href='#L303'>303</a>
|
|
369
|
+
<a name='L304'></a><a href='#L304'>304</a>
|
|
370
|
+
<a name='L305'></a><a href='#L305'>305</a>
|
|
371
|
+
<a name='L306'></a><a href='#L306'>306</a>
|
|
372
|
+
<a name='L307'></a><a href='#L307'>307</a>
|
|
373
|
+
<a name='L308'></a><a href='#L308'>308</a>
|
|
374
|
+
<a name='L309'></a><a href='#L309'>309</a>
|
|
375
|
+
<a name='L310'></a><a href='#L310'>310</a>
|
|
376
|
+
<a name='L311'></a><a href='#L311'>311</a>
|
|
377
|
+
<a name='L312'></a><a href='#L312'>312</a>
|
|
378
|
+
<a name='L313'></a><a href='#L313'>313</a>
|
|
379
|
+
<a name='L314'></a><a href='#L314'>314</a>
|
|
380
|
+
<a name='L315'></a><a href='#L315'>315</a>
|
|
381
|
+
<a name='L316'></a><a href='#L316'>316</a>
|
|
382
|
+
<a name='L317'></a><a href='#L317'>317</a>
|
|
383
|
+
<a name='L318'></a><a href='#L318'>318</a>
|
|
384
|
+
<a name='L319'></a><a href='#L319'>319</a>
|
|
385
|
+
<a name='L320'></a><a href='#L320'>320</a>
|
|
386
|
+
<a name='L321'></a><a href='#L321'>321</a>
|
|
387
|
+
<a name='L322'></a><a href='#L322'>322</a>
|
|
388
|
+
<a name='L323'></a><a href='#L323'>323</a>
|
|
389
|
+
<a name='L324'></a><a href='#L324'>324</a>
|
|
390
|
+
<a name='L325'></a><a href='#L325'>325</a>
|
|
391
|
+
<a name='L326'></a><a href='#L326'>326</a>
|
|
392
|
+
<a name='L327'></a><a href='#L327'>327</a>
|
|
393
|
+
<a name='L328'></a><a href='#L328'>328</a>
|
|
394
|
+
<a name='L329'></a><a href='#L329'>329</a>
|
|
395
|
+
<a name='L330'></a><a href='#L330'>330</a>
|
|
396
|
+
<a name='L331'></a><a href='#L331'>331</a>
|
|
397
|
+
<a name='L332'></a><a href='#L332'>332</a>
|
|
398
|
+
<a name='L333'></a><a href='#L333'>333</a>
|
|
399
|
+
<a name='L334'></a><a href='#L334'>334</a>
|
|
400
|
+
<a name='L335'></a><a href='#L335'>335</a>
|
|
401
|
+
<a name='L336'></a><a href='#L336'>336</a>
|
|
402
|
+
<a name='L337'></a><a href='#L337'>337</a>
|
|
403
|
+
<a name='L338'></a><a href='#L338'>338</a>
|
|
404
|
+
<a name='L339'></a><a href='#L339'>339</a>
|
|
405
|
+
<a name='L340'></a><a href='#L340'>340</a>
|
|
406
|
+
<a name='L341'></a><a href='#L341'>341</a>
|
|
407
|
+
<a name='L342'></a><a href='#L342'>342</a>
|
|
408
|
+
<a name='L343'></a><a href='#L343'>343</a>
|
|
409
|
+
<a name='L344'></a><a href='#L344'>344</a>
|
|
410
|
+
<a name='L345'></a><a href='#L345'>345</a>
|
|
411
|
+
<a name='L346'></a><a href='#L346'>346</a>
|
|
412
|
+
<a name='L347'></a><a href='#L347'>347</a>
|
|
413
|
+
<a name='L348'></a><a href='#L348'>348</a>
|
|
414
|
+
<a name='L349'></a><a href='#L349'>349</a>
|
|
415
|
+
<a name='L350'></a><a href='#L350'>350</a>
|
|
416
|
+
<a name='L351'></a><a href='#L351'>351</a>
|
|
417
|
+
<a name='L352'></a><a href='#L352'>352</a>
|
|
418
|
+
<a name='L353'></a><a href='#L353'>353</a>
|
|
419
|
+
<a name='L354'></a><a href='#L354'>354</a>
|
|
420
|
+
<a name='L355'></a><a href='#L355'>355</a>
|
|
421
|
+
<a name='L356'></a><a href='#L356'>356</a>
|
|
422
|
+
<a name='L357'></a><a href='#L357'>357</a>
|
|
423
|
+
<a name='L358'></a><a href='#L358'>358</a>
|
|
424
|
+
<a name='L359'></a><a href='#L359'>359</a>
|
|
425
|
+
<a name='L360'></a><a href='#L360'>360</a>
|
|
426
|
+
<a name='L361'></a><a href='#L361'>361</a>
|
|
427
|
+
<a name='L362'></a><a href='#L362'>362</a>
|
|
428
|
+
<a name='L363'></a><a href='#L363'>363</a>
|
|
429
|
+
<a name='L364'></a><a href='#L364'>364</a>
|
|
430
|
+
<a name='L365'></a><a href='#L365'>365</a>
|
|
431
|
+
<a name='L366'></a><a href='#L366'>366</a>
|
|
432
|
+
<a name='L367'></a><a href='#L367'>367</a>
|
|
433
|
+
<a name='L368'></a><a href='#L368'>368</a>
|
|
434
|
+
<a name='L369'></a><a href='#L369'>369</a>
|
|
435
|
+
<a name='L370'></a><a href='#L370'>370</a>
|
|
436
|
+
<a name='L371'></a><a href='#L371'>371</a>
|
|
437
|
+
<a name='L372'></a><a href='#L372'>372</a>
|
|
438
|
+
<a name='L373'></a><a href='#L373'>373</a>
|
|
439
|
+
<a name='L374'></a><a href='#L374'>374</a>
|
|
440
|
+
<a name='L375'></a><a href='#L375'>375</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
441
|
+
<span class="cline-any cline-neutral"> </span>
|
|
442
|
+
<span class="cline-any cline-neutral"> </span>
|
|
443
|
+
<span class="cline-any cline-neutral"> </span>
|
|
444
|
+
<span class="cline-any cline-neutral"> </span>
|
|
445
|
+
<span class="cline-any cline-neutral"> </span>
|
|
446
|
+
<span class="cline-any cline-neutral"> </span>
|
|
447
|
+
<span class="cline-any cline-neutral"> </span>
|
|
448
|
+
<span class="cline-any cline-neutral"> </span>
|
|
449
|
+
<span class="cline-any cline-neutral"> </span>
|
|
450
|
+
<span class="cline-any cline-neutral"> </span>
|
|
451
|
+
<span class="cline-any cline-neutral"> </span>
|
|
452
|
+
<span class="cline-any cline-neutral"> </span>
|
|
453
|
+
<span class="cline-any cline-neutral"> </span>
|
|
454
|
+
<span class="cline-any cline-neutral"> </span>
|
|
455
|
+
<span class="cline-any cline-neutral"> </span>
|
|
456
|
+
<span class="cline-any cline-neutral"> </span>
|
|
457
|
+
<span class="cline-any cline-neutral"> </span>
|
|
458
|
+
<span class="cline-any cline-neutral"> </span>
|
|
459
|
+
<span class="cline-any cline-neutral"> </span>
|
|
460
|
+
<span class="cline-any cline-neutral"> </span>
|
|
461
|
+
<span class="cline-any cline-neutral"> </span>
|
|
462
|
+
<span class="cline-any cline-neutral"> </span>
|
|
463
|
+
<span class="cline-any cline-neutral"> </span>
|
|
464
|
+
<span class="cline-any cline-neutral"> </span>
|
|
465
|
+
<span class="cline-any cline-neutral"> </span>
|
|
466
|
+
<span class="cline-any cline-neutral"> </span>
|
|
467
|
+
<span class="cline-any cline-neutral"> </span>
|
|
468
|
+
<span class="cline-any cline-neutral"> </span>
|
|
469
|
+
<span class="cline-any cline-neutral"> </span>
|
|
470
|
+
<span class="cline-any cline-neutral"> </span>
|
|
471
|
+
<span class="cline-any cline-neutral"> </span>
|
|
472
|
+
<span class="cline-any cline-neutral"> </span>
|
|
473
|
+
<span class="cline-any cline-neutral"> </span>
|
|
474
|
+
<span class="cline-any cline-neutral"> </span>
|
|
475
|
+
<span class="cline-any cline-neutral"> </span>
|
|
476
|
+
<span class="cline-any cline-neutral"> </span>
|
|
477
|
+
<span class="cline-any cline-neutral"> </span>
|
|
478
|
+
<span class="cline-any cline-neutral"> </span>
|
|
479
|
+
<span class="cline-any cline-neutral"> </span>
|
|
480
|
+
<span class="cline-any cline-neutral"> </span>
|
|
481
|
+
<span class="cline-any cline-neutral"> </span>
|
|
482
|
+
<span class="cline-any cline-neutral"> </span>
|
|
483
|
+
<span class="cline-any cline-neutral"> </span>
|
|
484
|
+
<span class="cline-any cline-neutral"> </span>
|
|
485
|
+
<span class="cline-any cline-neutral"> </span>
|
|
486
|
+
<span class="cline-any cline-neutral"> </span>
|
|
487
|
+
<span class="cline-any cline-neutral"> </span>
|
|
488
|
+
<span class="cline-any cline-neutral"> </span>
|
|
489
|
+
<span class="cline-any cline-neutral"> </span>
|
|
490
|
+
<span class="cline-any cline-yes">28x</span>
|
|
491
|
+
<span class="cline-any cline-neutral"> </span>
|
|
492
|
+
<span class="cline-any cline-neutral"> </span>
|
|
493
|
+
<span class="cline-any cline-neutral"> </span>
|
|
494
|
+
<span class="cline-any cline-neutral"> </span>
|
|
495
|
+
<span class="cline-any cline-neutral"> </span>
|
|
496
|
+
<span class="cline-any cline-neutral"> </span>
|
|
497
|
+
<span class="cline-any cline-neutral"> </span>
|
|
498
|
+
<span class="cline-any cline-yes">5x</span>
|
|
499
|
+
<span class="cline-any cline-neutral"> </span>
|
|
500
|
+
<span class="cline-any cline-neutral"> </span>
|
|
501
|
+
<span class="cline-any cline-neutral"> </span>
|
|
502
|
+
<span class="cline-any cline-neutral"> </span>
|
|
503
|
+
<span class="cline-any cline-neutral"> </span>
|
|
504
|
+
<span class="cline-any cline-neutral"> </span>
|
|
505
|
+
<span class="cline-any cline-neutral"> </span>
|
|
506
|
+
<span class="cline-any cline-neutral"> </span>
|
|
507
|
+
<span class="cline-any cline-neutral"> </span>
|
|
508
|
+
<span class="cline-any cline-neutral"> </span>
|
|
509
|
+
<span class="cline-any cline-neutral"> </span>
|
|
510
|
+
<span class="cline-any cline-neutral"> </span>
|
|
511
|
+
<span class="cline-any cline-yes">1x</span>
|
|
512
|
+
<span class="cline-any cline-neutral"> </span>
|
|
513
|
+
<span class="cline-any cline-neutral"> </span>
|
|
514
|
+
<span class="cline-any cline-neutral"> </span>
|
|
515
|
+
<span class="cline-any cline-neutral"> </span>
|
|
516
|
+
<span class="cline-any cline-neutral"> </span>
|
|
517
|
+
<span class="cline-any cline-neutral"> </span>
|
|
518
|
+
<span class="cline-any cline-neutral"> </span>
|
|
519
|
+
<span class="cline-any cline-neutral"> </span>
|
|
520
|
+
<span class="cline-any cline-neutral"> </span>
|
|
521
|
+
<span class="cline-any cline-neutral"> </span>
|
|
522
|
+
<span class="cline-any cline-neutral"> </span>
|
|
523
|
+
<span class="cline-any cline-neutral"> </span>
|
|
524
|
+
<span class="cline-any cline-neutral"> </span>
|
|
525
|
+
<span class="cline-any cline-neutral"> </span>
|
|
526
|
+
<span class="cline-any cline-neutral"> </span>
|
|
527
|
+
<span class="cline-any cline-neutral"> </span>
|
|
528
|
+
<span class="cline-any cline-yes">13x</span>
|
|
529
|
+
<span class="cline-any cline-neutral"> </span>
|
|
530
|
+
<span class="cline-any cline-neutral"> </span>
|
|
531
|
+
<span class="cline-any cline-neutral"> </span>
|
|
532
|
+
<span class="cline-any cline-yes">13x</span>
|
|
533
|
+
<span class="cline-any cline-yes">3x</span>
|
|
534
|
+
<span class="cline-any cline-neutral"> </span>
|
|
535
|
+
<span class="cline-any cline-neutral"> </span>
|
|
536
|
+
<span class="cline-any cline-neutral"> </span>
|
|
537
|
+
<span class="cline-any cline-neutral"> </span>
|
|
538
|
+
<span class="cline-any cline-neutral"> </span>
|
|
539
|
+
<span class="cline-any cline-yes">10x</span>
|
|
540
|
+
<span class="cline-any cline-neutral"> </span>
|
|
541
|
+
<span class="cline-any cline-neutral"> </span>
|
|
542
|
+
<span class="cline-any cline-neutral"> </span>
|
|
543
|
+
<span class="cline-any cline-neutral"> </span>
|
|
544
|
+
<span class="cline-any cline-neutral"> </span>
|
|
545
|
+
<span class="cline-any cline-neutral"> </span>
|
|
546
|
+
<span class="cline-any cline-neutral"> </span>
|
|
547
|
+
<span class="cline-any cline-neutral"> </span>
|
|
548
|
+
<span class="cline-any cline-neutral"> </span>
|
|
549
|
+
<span class="cline-any cline-neutral"> </span>
|
|
550
|
+
<span class="cline-any cline-neutral"> </span>
|
|
551
|
+
<span class="cline-any cline-neutral"> </span>
|
|
552
|
+
<span class="cline-any cline-neutral"> </span>
|
|
553
|
+
<span class="cline-any cline-neutral"> </span>
|
|
554
|
+
<span class="cline-any cline-neutral"> </span>
|
|
555
|
+
<span class="cline-any cline-neutral"> </span>
|
|
556
|
+
<span class="cline-any cline-neutral"> </span>
|
|
557
|
+
<span class="cline-any cline-neutral"> </span>
|
|
558
|
+
<span class="cline-any cline-neutral"> </span>
|
|
559
|
+
<span class="cline-any cline-yes">3x</span>
|
|
560
|
+
<span class="cline-any cline-neutral"> </span>
|
|
561
|
+
<span class="cline-any cline-neutral"> </span>
|
|
562
|
+
<span class="cline-any cline-neutral"> </span>
|
|
563
|
+
<span class="cline-any cline-yes">3x</span>
|
|
564
|
+
<span class="cline-any cline-yes">1x</span>
|
|
565
|
+
<span class="cline-any cline-neutral"> </span>
|
|
566
|
+
<span class="cline-any cline-neutral"> </span>
|
|
567
|
+
<span class="cline-any cline-neutral"> </span>
|
|
568
|
+
<span class="cline-any cline-neutral"> </span>
|
|
569
|
+
<span class="cline-any cline-neutral"> </span>
|
|
570
|
+
<span class="cline-any cline-yes">2x</span>
|
|
571
|
+
<span class="cline-any cline-neutral"> </span>
|
|
572
|
+
<span class="cline-any cline-neutral"> </span>
|
|
573
|
+
<span class="cline-any cline-neutral"> </span>
|
|
574
|
+
<span class="cline-any cline-neutral"> </span>
|
|
575
|
+
<span class="cline-any cline-neutral"> </span>
|
|
576
|
+
<span class="cline-any cline-neutral"> </span>
|
|
577
|
+
<span class="cline-any cline-neutral"> </span>
|
|
578
|
+
<span class="cline-any cline-neutral"> </span>
|
|
579
|
+
<span class="cline-any cline-neutral"> </span>
|
|
580
|
+
<span class="cline-any cline-neutral"> </span>
|
|
581
|
+
<span class="cline-any cline-neutral"> </span>
|
|
582
|
+
<span class="cline-any cline-neutral"> </span>
|
|
583
|
+
<span class="cline-any cline-yes">6x</span>
|
|
584
|
+
<span class="cline-any cline-neutral"> </span>
|
|
585
|
+
<span class="cline-any cline-neutral"> </span>
|
|
586
|
+
<span class="cline-any cline-neutral"> </span>
|
|
587
|
+
<span class="cline-any cline-yes">6x</span>
|
|
588
|
+
<span class="cline-any cline-neutral"> </span>
|
|
589
|
+
<span class="cline-any cline-neutral"> </span>
|
|
590
|
+
<span class="cline-any cline-neutral"> </span>
|
|
591
|
+
<span class="cline-any cline-neutral"> </span>
|
|
592
|
+
<span class="cline-any cline-neutral"> </span>
|
|
593
|
+
<span class="cline-any cline-neutral"> </span>
|
|
594
|
+
<span class="cline-any cline-neutral"> </span>
|
|
595
|
+
<span class="cline-any cline-neutral"> </span>
|
|
596
|
+
<span class="cline-any cline-neutral"> </span>
|
|
597
|
+
<span class="cline-any cline-neutral"> </span>
|
|
598
|
+
<span class="cline-any cline-yes">13x</span>
|
|
599
|
+
<span class="cline-any cline-neutral"> </span>
|
|
600
|
+
<span class="cline-any cline-neutral"> </span>
|
|
601
|
+
<span class="cline-any cline-neutral"> </span>
|
|
602
|
+
<span class="cline-any cline-neutral"> </span>
|
|
603
|
+
<span class="cline-any cline-neutral"> </span>
|
|
604
|
+
<span class="cline-any cline-neutral"> </span>
|
|
605
|
+
<span class="cline-any cline-neutral"> </span>
|
|
606
|
+
<span class="cline-any cline-neutral"> </span>
|
|
607
|
+
<span class="cline-any cline-neutral"> </span>
|
|
608
|
+
<span class="cline-any cline-neutral"> </span>
|
|
609
|
+
<span class="cline-any cline-yes">5x</span>
|
|
610
|
+
<span class="cline-any cline-neutral"> </span>
|
|
611
|
+
<span class="cline-any cline-neutral"> </span>
|
|
612
|
+
<span class="cline-any cline-neutral"> </span>
|
|
613
|
+
<span class="cline-any cline-neutral"> </span>
|
|
614
|
+
<span class="cline-any cline-neutral"> </span>
|
|
615
|
+
<span class="cline-any cline-neutral"> </span>
|
|
616
|
+
<span class="cline-any cline-neutral"> </span>
|
|
617
|
+
<span class="cline-any cline-neutral"> </span>
|
|
618
|
+
<span class="cline-any cline-neutral"> </span>
|
|
619
|
+
<span class="cline-any cline-neutral"> </span>
|
|
620
|
+
<span class="cline-any cline-neutral"> </span>
|
|
621
|
+
<span class="cline-any cline-neutral"> </span>
|
|
622
|
+
<span class="cline-any cline-neutral"> </span>
|
|
623
|
+
<span class="cline-any cline-neutral"> </span>
|
|
624
|
+
<span class="cline-any cline-neutral"> </span>
|
|
625
|
+
<span class="cline-any cline-neutral"> </span>
|
|
626
|
+
<span class="cline-any cline-neutral"> </span>
|
|
627
|
+
<span class="cline-any cline-neutral"> </span>
|
|
628
|
+
<span class="cline-any cline-neutral"> </span>
|
|
629
|
+
<span class="cline-any cline-neutral"> </span>
|
|
630
|
+
<span class="cline-any cline-yes">6x</span>
|
|
631
|
+
<span class="cline-any cline-neutral"> </span>
|
|
632
|
+
<span class="cline-any cline-neutral"> </span>
|
|
633
|
+
<span class="cline-any cline-yes">6x</span>
|
|
634
|
+
<span class="cline-any cline-yes">2x</span>
|
|
635
|
+
<span class="cline-any cline-neutral"> </span>
|
|
636
|
+
<span class="cline-any cline-neutral"> </span>
|
|
637
|
+
<span class="cline-any cline-neutral"> </span>
|
|
638
|
+
<span class="cline-any cline-neutral"> </span>
|
|
639
|
+
<span class="cline-any cline-neutral"> </span>
|
|
640
|
+
<span class="cline-any cline-neutral"> </span>
|
|
641
|
+
<span class="cline-any cline-yes">4x</span>
|
|
642
|
+
<span class="cline-any cline-yes">1x</span>
|
|
643
|
+
<span class="cline-any cline-neutral"> </span>
|
|
644
|
+
<span class="cline-any cline-neutral"> </span>
|
|
645
|
+
<span class="cline-any cline-neutral"> </span>
|
|
646
|
+
<span class="cline-any cline-neutral"> </span>
|
|
647
|
+
<span class="cline-any cline-neutral"> </span>
|
|
648
|
+
<span class="cline-any cline-neutral"> </span>
|
|
649
|
+
<span class="cline-any cline-yes">3x</span>
|
|
650
|
+
<span class="cline-any cline-yes">3x</span>
|
|
651
|
+
<span class="cline-any cline-yes">1x</span>
|
|
652
|
+
<span class="cline-any cline-neutral"> </span>
|
|
653
|
+
<span class="cline-any cline-neutral"> </span>
|
|
654
|
+
<span class="cline-any cline-neutral"> </span>
|
|
655
|
+
<span class="cline-any cline-neutral"> </span>
|
|
656
|
+
<span class="cline-any cline-neutral"> </span>
|
|
657
|
+
<span class="cline-any cline-yes">2x</span>
|
|
658
|
+
<span class="cline-any cline-neutral"> </span>
|
|
659
|
+
<span class="cline-any cline-neutral"> </span>
|
|
660
|
+
<span class="cline-any cline-neutral"> </span>
|
|
661
|
+
<span class="cline-any cline-neutral"> </span>
|
|
662
|
+
<span class="cline-any cline-neutral"> </span>
|
|
663
|
+
<span class="cline-any cline-neutral"> </span>
|
|
664
|
+
<span class="cline-any cline-neutral"> </span>
|
|
665
|
+
<span class="cline-any cline-neutral"> </span>
|
|
666
|
+
<span class="cline-any cline-neutral"> </span>
|
|
667
|
+
<span class="cline-any cline-neutral"> </span>
|
|
668
|
+
<span class="cline-any cline-neutral"> </span>
|
|
669
|
+
<span class="cline-any cline-neutral"> </span>
|
|
670
|
+
<span class="cline-any cline-neutral"> </span>
|
|
671
|
+
<span class="cline-any cline-neutral"> </span>
|
|
672
|
+
<span class="cline-any cline-neutral"> </span>
|
|
673
|
+
<span class="cline-any cline-neutral"> </span>
|
|
674
|
+
<span class="cline-any cline-neutral"> </span>
|
|
675
|
+
<span class="cline-any cline-neutral"> </span>
|
|
676
|
+
<span class="cline-any cline-neutral"> </span>
|
|
677
|
+
<span class="cline-any cline-neutral"> </span>
|
|
678
|
+
<span class="cline-any cline-neutral"> </span>
|
|
679
|
+
<span class="cline-any cline-neutral"> </span>
|
|
680
|
+
<span class="cline-any cline-neutral"> </span>
|
|
681
|
+
<span class="cline-any cline-neutral"> </span>
|
|
682
|
+
<span class="cline-any cline-neutral"> </span>
|
|
683
|
+
<span class="cline-any cline-neutral"> </span>
|
|
684
|
+
<span class="cline-any cline-neutral"> </span>
|
|
685
|
+
<span class="cline-any cline-neutral"> </span>
|
|
686
|
+
<span class="cline-any cline-yes">6x</span>
|
|
687
|
+
<span class="cline-any cline-neutral"> </span>
|
|
688
|
+
<span class="cline-any cline-neutral"> </span>
|
|
689
|
+
<span class="cline-any cline-yes">6x</span>
|
|
690
|
+
<span class="cline-any cline-yes">2x</span>
|
|
691
|
+
<span class="cline-any cline-yes">1x</span>
|
|
692
|
+
<span class="cline-any cline-neutral"> </span>
|
|
693
|
+
<span class="cline-any cline-neutral"> </span>
|
|
694
|
+
<span class="cline-any cline-neutral"> </span>
|
|
695
|
+
<span class="cline-any cline-neutral"> </span>
|
|
696
|
+
<span class="cline-any cline-neutral"> </span>
|
|
697
|
+
<span class="cline-any cline-yes">1x</span>
|
|
698
|
+
<span class="cline-any cline-yes">1x</span>
|
|
699
|
+
<span class="cline-any cline-yes">1x</span>
|
|
700
|
+
<span class="cline-any cline-neutral"> </span>
|
|
701
|
+
<span class="cline-any cline-neutral"> </span>
|
|
702
|
+
<span class="cline-any cline-neutral"> </span>
|
|
703
|
+
<span class="cline-any cline-neutral"> </span>
|
|
704
|
+
<span class="cline-any cline-neutral"> </span>
|
|
705
|
+
<span class="cline-any cline-neutral"> </span>
|
|
706
|
+
<span class="cline-any cline-neutral"> </span>
|
|
707
|
+
<span class="cline-any cline-yes">4x</span>
|
|
708
|
+
<span class="cline-any cline-yes">4x</span>
|
|
709
|
+
<span class="cline-any cline-yes">1x</span>
|
|
710
|
+
<span class="cline-any cline-neutral"> </span>
|
|
711
|
+
<span class="cline-any cline-neutral"> </span>
|
|
712
|
+
<span class="cline-any cline-neutral"> </span>
|
|
713
|
+
<span class="cline-any cline-neutral"> </span>
|
|
714
|
+
<span class="cline-any cline-yes">4x</span>
|
|
715
|
+
<span class="cline-any cline-neutral"> </span>
|
|
716
|
+
<span class="cline-any cline-neutral"> </span>
|
|
717
|
+
<span class="cline-any cline-neutral"> </span>
|
|
718
|
+
<span class="cline-any cline-neutral"> </span>
|
|
719
|
+
<span class="cline-any cline-yes">4x</span>
|
|
720
|
+
<span class="cline-any cline-yes">2x</span>
|
|
721
|
+
<span class="cline-any cline-neutral"> </span>
|
|
722
|
+
<span class="cline-any cline-neutral"> </span>
|
|
723
|
+
<span class="cline-any cline-yes">4x</span>
|
|
724
|
+
<span class="cline-any cline-neutral"> </span>
|
|
725
|
+
<span class="cline-any cline-neutral"> </span>
|
|
726
|
+
<span class="cline-any cline-neutral"> </span>
|
|
727
|
+
<span class="cline-any cline-neutral"> </span>
|
|
728
|
+
<span class="cline-any cline-neutral"> </span>
|
|
729
|
+
<span class="cline-any cline-neutral"> </span>
|
|
730
|
+
<span class="cline-any cline-neutral"> </span>
|
|
731
|
+
<span class="cline-any cline-neutral"> </span>
|
|
732
|
+
<span class="cline-any cline-neutral"> </span>
|
|
733
|
+
<span class="cline-any cline-neutral"> </span>
|
|
734
|
+
<span class="cline-any cline-neutral"> </span>
|
|
735
|
+
<span class="cline-any cline-neutral"> </span>
|
|
736
|
+
<span class="cline-any cline-neutral"> </span>
|
|
737
|
+
<span class="cline-any cline-neutral"> </span>
|
|
738
|
+
<span class="cline-any cline-neutral"> </span>
|
|
739
|
+
<span class="cline-any cline-neutral"> </span>
|
|
740
|
+
<span class="cline-any cline-yes">2x</span>
|
|
741
|
+
<span class="cline-any cline-neutral"> </span>
|
|
742
|
+
<span class="cline-any cline-neutral"> </span>
|
|
743
|
+
<span class="cline-any cline-yes">1x</span>
|
|
744
|
+
<span class="cline-any cline-neutral"> </span>
|
|
745
|
+
<span class="cline-any cline-neutral"> </span>
|
|
746
|
+
<span class="cline-any cline-yes">1x</span>
|
|
747
|
+
<span class="cline-any cline-neutral"> </span>
|
|
748
|
+
<span class="cline-any cline-neutral"> </span>
|
|
749
|
+
<span class="cline-any cline-neutral"> </span>
|
|
750
|
+
<span class="cline-any cline-neutral"> </span>
|
|
751
|
+
<span class="cline-any cline-neutral"> </span>
|
|
752
|
+
<span class="cline-any cline-neutral"> </span>
|
|
753
|
+
<span class="cline-any cline-yes">1x</span>
|
|
754
|
+
<span class="cline-any cline-yes">2x</span>
|
|
755
|
+
<span class="cline-any cline-neutral"> </span>
|
|
756
|
+
<span class="cline-any cline-neutral"> </span>
|
|
757
|
+
<span class="cline-any cline-neutral"> </span>
|
|
758
|
+
<span class="cline-any cline-neutral"> </span>
|
|
759
|
+
<span class="cline-any cline-neutral"> </span>
|
|
760
|
+
<span class="cline-any cline-yes">1x</span>
|
|
761
|
+
<span class="cline-any cline-neutral"> </span>
|
|
762
|
+
<span class="cline-any cline-neutral"> </span>
|
|
763
|
+
<span class="cline-any cline-neutral"> </span>
|
|
764
|
+
<span class="cline-any cline-yes">1x</span>
|
|
765
|
+
<span class="cline-any cline-neutral"> </span>
|
|
766
|
+
<span class="cline-any cline-neutral"> </span>
|
|
767
|
+
<span class="cline-any cline-neutral"> </span>
|
|
768
|
+
<span class="cline-any cline-neutral"> </span>
|
|
769
|
+
<span class="cline-any cline-neutral"> </span>
|
|
770
|
+
<span class="cline-any cline-neutral"> </span>
|
|
771
|
+
<span class="cline-any cline-neutral"> </span>
|
|
772
|
+
<span class="cline-any cline-neutral"> </span>
|
|
773
|
+
<span class="cline-any cline-neutral"> </span>
|
|
774
|
+
<span class="cline-any cline-neutral"> </span>
|
|
775
|
+
<span class="cline-any cline-neutral"> </span>
|
|
776
|
+
<span class="cline-any cline-neutral"> </span>
|
|
777
|
+
<span class="cline-any cline-neutral"> </span>
|
|
778
|
+
<span class="cline-any cline-neutral"> </span>
|
|
779
|
+
<span class="cline-any cline-neutral"> </span>
|
|
780
|
+
<span class="cline-any cline-neutral"> </span>
|
|
781
|
+
<span class="cline-any cline-neutral"> </span>
|
|
782
|
+
<span class="cline-any cline-yes">2x</span>
|
|
783
|
+
<span class="cline-any cline-neutral"> </span>
|
|
784
|
+
<span class="cline-any cline-yes">2x</span>
|
|
785
|
+
<span class="cline-any cline-yes">1x</span>
|
|
786
|
+
<span class="cline-any cline-neutral"> </span>
|
|
787
|
+
<span class="cline-any cline-neutral"> </span>
|
|
788
|
+
<span class="cline-any cline-neutral"> </span>
|
|
789
|
+
<span class="cline-any cline-yes">1x</span>
|
|
790
|
+
<span class="cline-any cline-yes">1x</span>
|
|
791
|
+
<span class="cline-any cline-neutral"> </span>
|
|
792
|
+
<span class="cline-any cline-neutral"> </span>
|
|
793
|
+
<span class="cline-any cline-neutral"> </span>
|
|
794
|
+
<span class="cline-any cline-neutral"> </span>
|
|
795
|
+
<span class="cline-any cline-neutral"> </span>
|
|
796
|
+
<span class="cline-any cline-neutral"> </span>
|
|
797
|
+
<span class="cline-any cline-neutral"> </span>
|
|
798
|
+
<span class="cline-any cline-neutral"> </span>
|
|
799
|
+
<span class="cline-any cline-neutral"> </span>
|
|
800
|
+
<span class="cline-any cline-neutral"> </span>
|
|
801
|
+
<span class="cline-any cline-neutral"> </span>
|
|
802
|
+
<span class="cline-any cline-neutral"> </span>
|
|
803
|
+
<span class="cline-any cline-neutral"> </span>
|
|
804
|
+
<span class="cline-any cline-neutral"> </span>
|
|
805
|
+
<span class="cline-any cline-neutral"> </span>
|
|
806
|
+
<span class="cline-any cline-neutral"> </span>
|
|
807
|
+
<span class="cline-any cline-neutral"> </span>
|
|
808
|
+
<span class="cline-any cline-neutral"> </span>
|
|
809
|
+
<span class="cline-any cline-yes">1x</span>
|
|
810
|
+
<span class="cline-any cline-neutral"> </span>
|
|
811
|
+
<span class="cline-any cline-neutral"> </span>
|
|
812
|
+
<span class="cline-any cline-neutral"> </span>
|
|
813
|
+
<span class="cline-any cline-neutral"> </span>
|
|
814
|
+
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">/**
|
|
815
|
+
* @fileoverview Realm configuration management service.
|
|
816
|
+
* Handles CRUD operations for Keycloak realm configurations stored in Strapi.
|
|
817
|
+
*
|
|
818
|
+
* @module services/realm
|
|
819
|
+
*/
|
|
820
|
+
|
|
821
|
+
import {
|
|
822
|
+
PLUGIN_ID,
|
|
823
|
+
CONTENT_TYPES,
|
|
824
|
+
SERVICES,
|
|
825
|
+
ERROR_MESSAGES,
|
|
826
|
+
DEFAULT_REALM_COLOR,
|
|
827
|
+
REALM_NAME_PATTERN,
|
|
828
|
+
} from '../constants.js';
|
|
829
|
+
import { createSanitizedError } from '../utils/errors.js';
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* @typedef {Object} RealmConfigData
|
|
833
|
+
* @property {string} name - Unique slug identifier (lowercase, hyphens only)
|
|
834
|
+
* @property {string} displayName - Human-readable name for UI
|
|
835
|
+
* @property {string} serverUrl - Keycloak server base URL
|
|
836
|
+
* @property {string} realmName - Keycloak realm name
|
|
837
|
+
* @property {string} clientId - Service account client ID
|
|
838
|
+
* @property {string} [clientSecret] - Service account client secret
|
|
839
|
+
* @property {boolean} [enabled=true] - Whether realm is active
|
|
840
|
+
* @property {string} [color] - UI accent color (hex)
|
|
841
|
+
*/
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* @typedef {Object} RealmConfig
|
|
845
|
+
* @property {string} documentId - Strapi document ID
|
|
846
|
+
* @property {string} name - Unique slug identifier
|
|
847
|
+
* @property {string} displayName - Human-readable name
|
|
848
|
+
* @property {string} serverUrl - Keycloak server URL
|
|
849
|
+
* @property {string} realmName - Keycloak realm name
|
|
850
|
+
* @property {string} clientId - Client ID
|
|
851
|
+
* @property {boolean} enabled - Active status
|
|
852
|
+
* @property {string} color - UI color
|
|
853
|
+
* @property {Date} createdAt - Creation timestamp
|
|
854
|
+
* @property {Date} updatedAt - Last update timestamp
|
|
855
|
+
*/
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Creates the realm configuration service.
|
|
859
|
+
*
|
|
860
|
+
* @param {Object} params - Service parameters
|
|
861
|
+
* @param {Object} params.strapi - Strapi instance
|
|
862
|
+
* @returns {Object} Realm service methods
|
|
863
|
+
*/
|
|
864
|
+
const realmService = ({ strapi }) => ({
|
|
865
|
+
/**
|
|
866
|
+
* Gets the Keycloak client service instance.
|
|
867
|
+
*
|
|
868
|
+
* @returns {Object} Keycloak client service
|
|
869
|
+
* @private
|
|
870
|
+
*/
|
|
871
|
+
get keycloakClient() {
|
|
872
|
+
return strapi.plugin(PLUGIN_ID).service(SERVICES.KEYCLOAK_CLIENT);
|
|
873
|
+
},
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* Retrieves all realm configurations.
|
|
877
|
+
* Note: clientSecret is not included in results (private field).
|
|
878
|
+
*
|
|
879
|
+
* @returns {Promise<RealmConfig[]>} Array of realm configurations sorted by displayName
|
|
880
|
+
*
|
|
881
|
+
* @example
|
|
882
|
+
* const realms = await realmService.findAll();
|
|
883
|
+
*/
|
|
884
|
+
async findAll() {
|
|
885
|
+
return strapi.documents(CONTENT_TYPES.REALM_CONFIG).findMany({
|
|
886
|
+
sort: { displayName: 'asc' },
|
|
887
|
+
});
|
|
888
|
+
},
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Retrieves a single realm by document ID.
|
|
892
|
+
* Note: clientSecret is not included (private field).
|
|
893
|
+
*
|
|
894
|
+
* @param {string} documentId - Strapi document ID
|
|
895
|
+
* @returns {Promise<RealmConfig>} Realm configuration
|
|
896
|
+
* @throws {Error} If realm not found
|
|
897
|
+
*
|
|
898
|
+
* @example
|
|
899
|
+
* const realm = await realmService.findOne('abc123');
|
|
900
|
+
*/
|
|
901
|
+
async findOne(documentId) {
|
|
902
|
+
const realm = await strapi.documents(CONTENT_TYPES.REALM_CONFIG).findOne({
|
|
903
|
+
documentId,
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
if (!realm) {
|
|
907
|
+
throw createSanitizedError(
|
|
908
|
+
`Realm ${documentId} not found`,
|
|
909
|
+
ERROR_MESSAGES.REALM_NOT_FOUND
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
return realm;
|
|
914
|
+
},
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Retrieves a realm with its clientSecret for internal Keycloak API calls.
|
|
918
|
+
* Uses db.query to bypass Strapi's private field sanitization.
|
|
919
|
+
*
|
|
920
|
+
* SECURITY: Only use this method when the clientSecret is actually needed
|
|
921
|
+
* for Keycloak authentication. Never expose the result to API responses.
|
|
922
|
+
*
|
|
923
|
+
* @param {string} documentId - Strapi document ID
|
|
924
|
+
* @returns {Promise<RealmConfig & {clientSecret: string}>} Full realm config with secret
|
|
925
|
+
* @throws {Error} If realm not found
|
|
926
|
+
*
|
|
927
|
+
* @example
|
|
928
|
+
* // Internal use only - for Keycloak API calls
|
|
929
|
+
* const realm = await realmService.findOneWithSecret(documentId);
|
|
930
|
+
* const token = await keycloakClient.getAccessToken(realm);
|
|
931
|
+
*/
|
|
932
|
+
async findOneWithSecret(documentId) {
|
|
933
|
+
const realm = await strapi.db.query(CONTENT_TYPES.REALM_CONFIG).findOne({
|
|
934
|
+
where: { documentId },
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
if (!realm) {
|
|
938
|
+
throw createSanitizedError(
|
|
939
|
+
`Realm ${documentId} not found`,
|
|
940
|
+
ERROR_MESSAGES.REALM_NOT_FOUND
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
return realm;
|
|
945
|
+
},
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Finds a realm by its unique slug name.
|
|
949
|
+
*
|
|
950
|
+
* @param {string} name - Realm slug name
|
|
951
|
+
* @returns {Promise<RealmConfig|null>} Realm configuration or null if not found
|
|
952
|
+
*
|
|
953
|
+
* @example
|
|
954
|
+
* const realm = await realmService.findByName('production-users');
|
|
955
|
+
*/
|
|
956
|
+
async findByName(name) {
|
|
957
|
+
const realms = await strapi.documents(CONTENT_TYPES.REALM_CONFIG).findMany({
|
|
958
|
+
filters: { name },
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
return realms[0] || null;
|
|
962
|
+
},
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Validates realm name format.
|
|
966
|
+
*
|
|
967
|
+
* @param {string} name - Name to validate
|
|
968
|
+
* @returns {boolean} True if valid
|
|
969
|
+
* @private
|
|
970
|
+
*/
|
|
971
|
+
isValidName(name) {
|
|
972
|
+
return REALM_NAME_PATTERN.test(name);
|
|
973
|
+
},
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* Normalizes a server URL by removing trailing slashes.
|
|
977
|
+
*
|
|
978
|
+
* @param {string} url - URL to normalize
|
|
979
|
+
* @returns {string} Normalized URL
|
|
980
|
+
* @private
|
|
981
|
+
*/
|
|
982
|
+
normalizeServerUrl(url) {
|
|
983
|
+
return url.replace(/\/$/, '');
|
|
984
|
+
},
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* Creates a new realm configuration.
|
|
988
|
+
*
|
|
989
|
+
* @param {RealmConfigData} data - Realm configuration data
|
|
990
|
+
* @returns {Promise<RealmConfig>} Created realm configuration
|
|
991
|
+
* @throws {Error} If validation fails or name already exists
|
|
992
|
+
*
|
|
993
|
+
* @example
|
|
994
|
+
* const realm = await realmService.create({
|
|
995
|
+
* name: 'production-users',
|
|
996
|
+
* displayName: 'Production Users',
|
|
997
|
+
* serverUrl: 'https://keycloak.example.com',
|
|
998
|
+
* realmName: 'production',
|
|
999
|
+
* clientId: 'strapi-admin',
|
|
1000
|
+
* clientSecret: 'secret-value'
|
|
1001
|
+
* });
|
|
1002
|
+
*/
|
|
1003
|
+
async create(data) {
|
|
1004
|
+
const { name, displayName, serverUrl, realmName, clientId, clientSecret } = data;
|
|
1005
|
+
|
|
1006
|
+
// Validate required fields
|
|
1007
|
+
if (!name || !displayName || !serverUrl || !realmName || !clientId) {
|
|
1008
|
+
throw createSanitizedError(
|
|
1009
|
+
'Missing required fields',
|
|
1010
|
+
ERROR_MESSAGES.MISSING_REQUIRED_FIELDS
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// Validate name format
|
|
1015
|
+
if (!this.isValidName(name)) {
|
|
1016
|
+
throw createSanitizedError(
|
|
1017
|
+
`Invalid name format: ${name}`,
|
|
1018
|
+
ERROR_MESSAGES.INVALID_NAME_FORMAT
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// Check for duplicate name
|
|
1023
|
+
const existing = await this.findByName(name);
|
|
1024
|
+
if (existing) {
|
|
1025
|
+
throw createSanitizedError(
|
|
1026
|
+
`Realm with name ${name} already exists`,
|
|
1027
|
+
ERROR_MESSAGES.REALM_NAME_EXISTS
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
return strapi.documents(CONTENT_TYPES.REALM_CONFIG).create({
|
|
1032
|
+
data: {
|
|
1033
|
+
name,
|
|
1034
|
+
displayName,
|
|
1035
|
+
serverUrl: this.normalizeServerUrl(serverUrl),
|
|
1036
|
+
realmName,
|
|
1037
|
+
clientId,
|
|
1038
|
+
clientSecret: clientSecret || null,
|
|
1039
|
+
enabled: data.enabled !== false,
|
|
1040
|
+
color: data.color || DEFAULT_REALM_COLOR,
|
|
1041
|
+
},
|
|
1042
|
+
});
|
|
1043
|
+
},
|
|
1044
|
+
|
|
1045
|
+
/**
|
|
1046
|
+
* Updates an existing realm configuration.
|
|
1047
|
+
*
|
|
1048
|
+
* @param {string} documentId - Strapi document ID
|
|
1049
|
+
* @param {Partial<RealmConfigData>} data - Fields to update
|
|
1050
|
+
* @returns {Promise<RealmConfig>} Updated realm configuration
|
|
1051
|
+
* @throws {Error} If validation fails or realm not found
|
|
1052
|
+
*
|
|
1053
|
+
* @example
|
|
1054
|
+
* const updated = await realmService.update(documentId, {
|
|
1055
|
+
* displayName: 'New Display Name',
|
|
1056
|
+
* enabled: false
|
|
1057
|
+
* });
|
|
1058
|
+
*/
|
|
1059
|
+
async update(documentId, data) {
|
|
1060
|
+
const existing = await this.findOne(documentId);
|
|
1061
|
+
|
|
1062
|
+
// Validate name change if applicable
|
|
1063
|
+
if (data.name && data.name !== existing.name) {
|
|
1064
|
+
if (!this.isValidName(data.name)) {
|
|
1065
|
+
throw createSanitizedError(
|
|
1066
|
+
`Invalid name format: ${data.name}`,
|
|
1067
|
+
ERROR_MESSAGES.INVALID_NAME_FORMAT
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
const duplicate = await this.findByName(data.name);
|
|
1072
|
+
<span class="missing-if-branch" title="else path not taken" >E</span>if (duplicate && duplicate.documentId !== documentId) {
|
|
1073
|
+
throw createSanitizedError(
|
|
1074
|
+
`Realm with name ${data.name} already exists`,
|
|
1075
|
+
ERROR_MESSAGES.REALM_NAME_EXISTS
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// Prepare update data
|
|
1081
|
+
const updateData = { ...data };
|
|
1082
|
+
if (updateData.serverUrl) {
|
|
1083
|
+
updateData.serverUrl = this.normalizeServerUrl(updateData.serverUrl);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// Clear token cache if connection details changed
|
|
1087
|
+
const connectionFieldsChanged =
|
|
1088
|
+
updateData.serverUrl ||
|
|
1089
|
+
updateData.realmName ||
|
|
1090
|
+
updateData.clientId ||
|
|
1091
|
+
updateData.clientSecret;
|
|
1092
|
+
|
|
1093
|
+
if (connectionFieldsChanged) {
|
|
1094
|
+
this.keycloakClient.clearTokenCache(existing);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
return strapi.documents(CONTENT_TYPES.REALM_CONFIG).update({
|
|
1098
|
+
documentId,
|
|
1099
|
+
data: updateData,
|
|
1100
|
+
});
|
|
1101
|
+
},
|
|
1102
|
+
|
|
1103
|
+
/**
|
|
1104
|
+
* Deletes a realm configuration and all associated admin assignments.
|
|
1105
|
+
*
|
|
1106
|
+
* @param {string} documentId - Strapi document ID
|
|
1107
|
+
* @returns {Promise<{success: boolean}>} Success indicator
|
|
1108
|
+
* @throws {Error} If realm not found
|
|
1109
|
+
*
|
|
1110
|
+
* @example
|
|
1111
|
+
* await realmService.delete(documentId);
|
|
1112
|
+
*/
|
|
1113
|
+
async delete(documentId) {
|
|
1114
|
+
const realm = await this.findOne(documentId);
|
|
1115
|
+
|
|
1116
|
+
// Clear token cache
|
|
1117
|
+
this.keycloakClient.clearTokenCache(realm);
|
|
1118
|
+
|
|
1119
|
+
// Delete all realm admin assignments for this realm
|
|
1120
|
+
const assignments = await strapi.documents(CONTENT_TYPES.REALM_ADMIN).findMany({
|
|
1121
|
+
filters: {
|
|
1122
|
+
realmConfig: { documentId },
|
|
1123
|
+
},
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
// Delete assignments sequentially to avoid race conditions
|
|
1127
|
+
for (const assignment of assignments) {
|
|
1128
|
+
await strapi.documents(CONTENT_TYPES.REALM_ADMIN).delete({
|
|
1129
|
+
documentId: assignment.documentId,
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// Delete the realm config
|
|
1134
|
+
await strapi.documents(CONTENT_TYPES.REALM_CONFIG).delete({
|
|
1135
|
+
documentId,
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
return { success: true };
|
|
1139
|
+
},
|
|
1140
|
+
|
|
1141
|
+
/**
|
|
1142
|
+
* Tests connection to a saved realm configuration.
|
|
1143
|
+
*
|
|
1144
|
+
* @param {string} documentId - Strapi document ID
|
|
1145
|
+
* @returns {Promise<{success: boolean, message?: string, realmDisplayName?: string}>} Test result
|
|
1146
|
+
*
|
|
1147
|
+
* @example
|
|
1148
|
+
* const result = await realmService.testConnection(documentId);
|
|
1149
|
+
* if (result.success) {
|
|
1150
|
+
* console.log(`Connected to ${result.realmDisplayName}`);
|
|
1151
|
+
* } else {
|
|
1152
|
+
* console.error(result.message);
|
|
1153
|
+
* }
|
|
1154
|
+
*/
|
|
1155
|
+
async testConnection(documentId) {
|
|
1156
|
+
const realmBasic = await this.findOne(documentId);
|
|
1157
|
+
|
|
1158
|
+
if (!realmBasic.enabled) {
|
|
1159
|
+
return { success: false, message: ERROR_MESSAGES.REALM_DISABLED };
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// Get realm with clientSecret for Keycloak connection
|
|
1163
|
+
const realm = await this.findOneWithSecret(documentId);
|
|
1164
|
+
return this.keycloakClient.testConnection(realm);
|
|
1165
|
+
},
|
|
1166
|
+
|
|
1167
|
+
/**
|
|
1168
|
+
* Tests connection with raw configuration data (before saving).
|
|
1169
|
+
* Useful for validating credentials during realm creation/editing.
|
|
1170
|
+
*
|
|
1171
|
+
* @param {RealmConfigData} config - Raw realm configuration
|
|
1172
|
+
* @returns {Promise<{success: boolean, message?: string, realmDisplayName?: string}>} Test result
|
|
1173
|
+
*
|
|
1174
|
+
* @example
|
|
1175
|
+
* const result = await realmService.testConnectionRaw({
|
|
1176
|
+
* serverUrl: 'https://keycloak.example.com',
|
|
1177
|
+
* realmName: 'my-realm',
|
|
1178
|
+
* clientId: 'strapi-admin',
|
|
1179
|
+
* clientSecret: 'secret'
|
|
1180
|
+
* });
|
|
1181
|
+
*/
|
|
1182
|
+
async testConnectionRaw(config) {
|
|
1183
|
+
return this.keycloakClient.testConnection(config);
|
|
1184
|
+
},
|
|
1185
|
+
});
|
|
1186
|
+
|
|
1187
|
+
export default realmService;
|
|
1188
|
+
</pre></td></tr></table></pre>
|
|
1189
|
+
|
|
1190
|
+
<div class='push'></div><!-- for sticky footer -->
|
|
1191
|
+
</div><!-- /wrapper -->
|
|
1192
|
+
<div class='footer quiet pad2 space-top1 center small'>
|
|
1193
|
+
Code coverage generated by
|
|
1194
|
+
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
1195
|
+
at 2026-02-05T14:19:59.409Z
|
|
1196
|
+
</div>
|
|
1197
|
+
<script src="../../prettify.js"></script>
|
|
1198
|
+
<script>
|
|
1199
|
+
window.onload = function () {
|
|
1200
|
+
prettyPrint();
|
|
1201
|
+
};
|
|
1202
|
+
</script>
|
|
1203
|
+
<script src="../../sorter.js"></script>
|
|
1204
|
+
<script src="../../block-navigation.js"></script>
|
|
1205
|
+
</body>
|
|
1206
|
+
</html>
|
|
1207
|
+
|