hive.mako 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. ## Licensed to Cloudera, Inc. under one
  2. ## or more contributor license agreements. See the NOTICE file
  3. ## distributed with this work for additional information
  4. ## regarding copyright ownership. Cloudera, Inc. licenses this file
  5. ## to you under the Apache License, Version 2.0 (the
  6. ## "License"); you may not use this file except in compliance
  7. ## with the License. You may obtain a copy of the License at
  8. ##
  9. ## http://www.apache.org/licenses/LICENSE-2.0
  10. ##
  11. ## Unless required by applicable law or agreed to in writing, software
  12. ## distributed under the License is distributed on an "AS IS" BASIS,
  13. ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ## See the License for the specific language governing permissions and
  15. ## limitations under the License.
  16. <%!
  17. from desktop.views import commonheader, commonfooter
  18. from django.utils.translation import ugettext as _
  19. %>
  20. <%namespace name="actionbar" file="actionbar.mako" />
  21. <%namespace name="layout" file="layout.mako" />
  22. <%namespace name="tree" file="common_tree.mako" />
  23. ${ commonheader(_('Hadoop Security'), "security", user) | n,unicode }
  24. ${ layout.menubar(section='hive') }
  25. <script type="text/html" id="role">
  26. <div class="acl-block-title">
  27. <i class="fa fa-cube muted"></i> <a class="pointer" data-bind="click: function(){ $root.showRole($data); }"><span data-bind="text: name"></span></a>
  28. </div>
  29. <div data-bind="template: { name: 'privilege', foreach: privilegesForView }"></div>
  30. <!-- ko ifnot: $root.isApplyingBulk() -->
  31. <div class="acl-block acl-actions">
  32. <span class="pointer" data-bind="visible: privilegesForViewTo() < privileges().length, click: function(){ privilegesForViewTo(privilegesForViewTo() + 50) }" title="${ _('Show 50 more...') }"><i class="fa fa-ellipsis-h"></i></span>
  33. <span class="pointer" data-bind="click: addPrivilege" title="${ _('Add privilege') }"><i class="fa fa-plus"></i></span>
  34. <span class="pointer" data-bind="click: function() { $root.list_sentry_privileges_by_authorizable() }, visible: privilegesChanged().length > 0" title="${ _('Undo') }"> &nbsp; <i class="fa fa-undo"></i></span>
  35. <span class="pointer" data-bind="click: function() { deletePrivilegeModal($data) }, visible: privilegesChanged().length > 0" title="${ _('Save') }"> &nbsp; <i class="fa fa-save"></i></span>
  36. </div>
  37. <!-- /ko -->
  38. </script>
  39. <script type="text/html" id="privilege">
  40. <div data-bind="visible: status() != 'deleted' && status() != 'alreadydeleted'" class="acl-block acl-block-airy">
  41. <!-- ko if: editing() -->
  42. <div class="pull-right">
  43. <a title="${ _('Grant this privilege') }" class="pointer" style="margin-right: 4px" data-bind="visible: grantOption() || $root.is_sentry_admin, click: function(){ $root.grantToPrivilege($data); $('#grantPrivilegeModal').modal('show'); }">
  44. <i class="fa fa-send"></i>
  45. </a>
  46. <a class="pointer" style="margin-right: 4px" data-bind="click: function() { if (editing()) { editing(false); }}"><i class="fa fa-eye"></i></a>
  47. <a class="pointer" style="margin-right: 4px" data-bind="click: remove"><i class="fa fa-times"></i></a>
  48. </div>
  49. <div class="inline-block" style="vertical-align: middle">
  50. <a class="pointer" style="padding-top: 4px" data-bind="click: function(){ privilegeType('db'); }">
  51. <i class="fa fa-fw fa-1halfx muted" data-bind="css: {'fa-circle-o': privilegeType() != 'db' , 'fa-check-circle-o': privilegeType() == 'db'}"></i>
  52. </a>
  53. </div>
  54. <input type="text" data-bind="hivechooser: $data.path, enable: privilegeType() == 'db'" placeholder="dbName.tableName <CTRL+SPACE>">
  55. <div class="inline-block" style="vertical-align: middle">
  56. <a class="pointer" style="padding-top: 4px" data-bind="click: function(){ privilegeType('uri'); }">
  57. <i class="fa fa-fw fa-1halfx muted" data-bind="css: {'fa-circle-o': privilegeType() != 'uri' , 'fa-check-circle-o': privilegeType() == 'uri'}"></i>
  58. </a>
  59. </div>
  60. <input type="text" data-bind="filechooser: $data.URI, enable: privilegeType() == 'uri'" placeholder="URI">
  61. <select data-bind="options: $root.availableActions, select2: { update: $data.action, type: 'action'}" style="width: 100px"></select>
  62. <div class="inline-block" style="vertical-align: middle">
  63. <label>&nbsp;&nbsp;<input type="checkbox" data-bind="checked: grantOption"> ${ _('With grant') }</label>
  64. </div>
  65. <span class="showAdvancedSpace">&nbsp;&nbsp;</span>
  66. <a class="pointer showAdvanced" data-bind="click: function(){ showAdvanced(true); }, visible: ! showAdvanced()"><i class="fa fa-cog"></i> ${ _('Advanced') }</a>
  67. <div class="acl-block-section" data-bind="visible: showAdvanced">
  68. <input type="text" data-bind="value: serverName" placeholder="serverName" style="margin-left: 29px">
  69. <select data-bind="options: $root.availablePrivileges, select2: { update: $data.privilegeScope, type: 'scope'}" style="width: 100px"></select>
  70. </div>
  71. <!-- /ko -->
  72. <!-- ko ifnot: editing() -->
  73. <!-- ko ifnot: $root.isApplyingBulk() -->
  74. <div class="pull-right">
  75. <a title="${ _('Grant this privilege') }" class="pointer" style="margin-right: 4px" data-bind="visible: grantOption() || $root.is_sentry_admin, click: function(){ $root.grantToPrivilege($data); $('#grantPrivilegeModal').modal('show'); }">
  76. <i class="fa fa-send"></i>
  77. </a>
  78. <a title="${ _('Edit this privilege') }" class="pointer" style="margin-right: 4px" data-bind="click: function() { if (! editing()) { editing(true); }}"><i class="fa fa-pencil"></i></a>
  79. <a title="${ _('Delete this privilege') }" class="pointer" style="margin-right: 4px" data-bind="click: remove"><i class="fa fa-times"></i></a>
  80. </div>
  81. <!-- /ko -->
  82. <em class="muted" data-bind="text: moment(timestamp()).fromNow()"></em> <span class="muted" data-bind="text: privilegeScope"></span>
  83. <!-- ko if: grantOption -->
  84. <i class="fa fa-unlock muted" title="${ _('With grant option') }"></i>
  85. <!-- /ko -->
  86. <br/>
  87. server=<span data-bind="text: serverName"></span>
  88. <!-- ko ifnot: URI -->
  89. <span data-bind="visible: dbName">
  90. <i class="fa fa-long-arrow-right"></i> db=<a data-bind="attr: { href: '/metastore/tables/' + dbName() }" target="_blank"><span data-bind="text: dbName"></span></a>
  91. </span>
  92. <span data-bind="visible: tableName">
  93. <i class="fa fa-long-arrow-right"></i> table=<a data-bind="attr: { href: '/metastore/table/' + dbName() + '/' + tableName() }" target="_blank"><span data-bind="text: tableName"></span></a>
  94. </span>
  95. <!-- /ko -->
  96. <!-- ko if: URI -->
  97. <i class="fa fa-long-arrow-right"></i> <a data-bind="attr: { href: '/filebrowser/view/' + URI().split('/')[3] }" target="_blank"><span data-bind="text: URI"></span></a>
  98. <!-- /ko -->
  99. <i class="fa fa-long-arrow-right"></i> action=<span data-bind="text: action"></span>
  100. <!-- /ko -->
  101. </div>
  102. </script>
  103. <div class="container-fluid">
  104. <div class="row-fluid">
  105. <div class="span2">
  106. <div class="sidebar-nav">
  107. <ul class="nav nav-list">
  108. <li class="nav-header">${ _('Privileges') }</li>
  109. <li class="active"><a href="javascript:void(0)" data-toggleSection="edit"><i class="fa fa-sitemap fa-rotate-270"></i> ${ _('Browse') }</a></li>
  110. <li><a href="javascript:void(0)" data-toggleSection="roles"><i class="fa fa-cubes"></i> ${ _('Roles') }</a></li>
  111. <li class="nav-header"><i class="fa fa-group"></i> ${ _('Groups') }
  112. <div>
  113. <br/>
  114. <select id="selectedGroup" data-bind="options: $root.selectableHadoopGroups, select2: { update: $data.action, type: 'action', allowClear: true }" style="width: 100%"></select>
  115. </div>
  116. </li>
  117. </ul>
  118. </div>
  119. </div>
  120. <div class="span10">
  121. <div id="edit" class="mainSection card card-small">
  122. <h1 class="card-heading simple">
  123. ${ _('Database and Tables privileges') }
  124. </h1>
  125. <div class="card-body">
  126. <div class="row-fluid" data-bind="visible: $root.doAs() != '${ user.username }' && ! $root.assist.isDiffMode()">
  127. <div class="span12">
  128. <div class="alert"><i class="fa fa-warning"></i> ${ _('You are currently impersonating the user') } <strong data-bind="text: $root.doAs"></strong></div>
  129. </div>
  130. </div>
  131. <div class="row-fluid">
  132. <div class="span6">
  133. <div class="path-container">
  134. <div class="input-append span12">
  135. <input id="path" class="path" type="text" autocomplete="off" />
  136. <a data-bind="attr: { href: '/metastore/table/' + $root.assist.path().replace('.', '/') }" target="_blank" title="${ _('Open in Metastore Browser') }" class="btn btn-inverse">
  137. <i class="fa fa-external-link"></i>
  138. </a>
  139. </div>
  140. <div class="clearfix"></div>
  141. <div class="tree-toolbar">
  142. <div class="pull-right">
  143. % if has_impersonation_perm:
  144. <div class="dropdown inline-block" style="margin-right: 6px">
  145. <a class="dropdown-toggle" data-toggle="dropdown" href="#">
  146. <i class="fa fa-eye-slash" data-bind="visible: $root.assist.isDiffMode"></i>
  147. <i class="fa fa-eye" data-bind="visible: ! $root.assist.isDiffMode()"></i>
  148. <span data-bind="visible: $root.assist.isDiffMode">${ _('Show non accessible paths for') }</span>
  149. <span data-bind="visible: ! $root.assist.isDiffMode()">${ _('Impersonate the user') }</span>
  150. </a>
  151. <ul class="dropdown-menu">
  152. <li data-bind="visible: ! $root.assist.isDiffMode(), click: function() { $root.assist.isDiffMode(true); }">
  153. <a tabindex="-1" href="#">${ _('Show non accessible paths for') }</a>
  154. </li>
  155. <li data-bind="visible: $root.assist.isDiffMode(), click: function() { $root.assist.isDiffMode(false); }">
  156. <a tabindex="-1" href="#">${ _('Impersonate the user') }</a>
  157. </li>
  158. </ul>
  159. </div>
  160. <select class="user-list" data-bind="options: $root.selectableHadoopUsers, select2: { placeholder: '${ _("Select a user") }', update: $root.doAs, type: 'user'}" style="width: 120px"></select>
  161. % endif
  162. </div>
  163. <div>
  164. <a class="pointer" data-bind="click: $root.assist.collapseOthers" rel="tooltip" data-placement="right" title="${_('Close other nodes')}">
  165. <i class="fa fa-compress"></i>
  166. </a>
  167. &nbsp;
  168. <a class="pointer" data-bind="click: $root.assist.refreshTree" rel="tooltip" data-placement="right" title="${_('Refresh the tree')}">
  169. <i class="fa fa-refresh"></i>
  170. </a>
  171. &nbsp;
  172. <a class="pointer" data-bind="visible: $root.assist.checkedItems().length > 0, click: function(){ $root.isApplyingBulk(true); $('#bulkActionsModal').modal('show'); }" rel="tooltip" data-placement="right" title="${ _('Add, replace or remove ACLs for the checked paths') }">
  173. <i class="fa fa-copy"></i>
  174. </a>
  175. &nbsp;
  176. <i class="fa fa-spinner fa-spin" data-bind="visible: $root.assist.isLoadingTree()"></i>
  177. </div>
  178. </div>
  179. </div>
  180. ${ tree.render(id='expandableTree', data='$root.assist.treeData', afterRender='$root.assist.afterRender') }
  181. </div>
  182. <div class="span6 acl-panel">
  183. <div class="acl-panel-content">
  184. <div class="pull-right">
  185. <input class="input-medium no-margin" type="text" placeholder="${ _('Search privileges...') }" data-bind="value: privilegeFilter, valueUpdate: 'afterkeydown', visible: $root.assist.privileges().length > 1"> &nbsp;
  186. <a data-bind="visible: $root.assist.privileges().length > 0 && $root.is_sentry_admin, click: function(){ $root.showCreateRole(true); $('#createRoleModal').modal('show'); }" class="btn pointer">
  187. <i class="fa fa-plus-circle"></i> ${ _('Add role') }
  188. </a>
  189. </div>
  190. <div data-bind="visible: $root.assist.privileges().length == 0 && $root.isLoadingPrivileges()"><i class="fa fa-spinner fa-spin" data-bind="visible: $root.isLoadingPrivileges()"></i> <em class="muted">${ _('Loading privileges...')}</em></div>
  191. <h4 style="margin-top: 4px" data-bind="visible: $root.assist.privileges().length > 0 && ! $root.isLoadingPrivileges()">${ _('Privileges') } &nbsp;</h4>
  192. <div data-bind="visible: $root.assist.privileges().length == 0 && ! $root.isLoadingPrivileges()">
  193. <div class="span10 offset1 center" style="cursor: pointer" data-bind="click: function(){ if ($root.is_sentry_admin) { $root.showCreateRole(true); $('#createRoleModal').modal('show'); } }">
  194. <i class="fa fa-plus-circle waiting"></i>
  195. <h1 class="emptyMessage">
  196. ${ _('No privileges found for the selected item') }<br/>
  197. <a class="pointer" data-bind="visible: $root.is_sentry_admin">${ _('Click here to add a new role') }</a>
  198. </h1>
  199. </div>
  200. </div>
  201. <div data-bind="template: { name: 'role', foreach: $root.assist.roles }"></div>
  202. </div>
  203. </div>
  204. </div>
  205. </div>
  206. </div>
  207. <div id="roles" class="mainSection hide card card-small">
  208. <h1 class="card-heading simple">
  209. ${ _('Roles') }
  210. </h1>
  211. <div class="card-body">
  212. <h1 class="muted" data-bind="visible: $root.isLoadingRoles()"><i class="fa fa-spinner fa-spin"></i></h1>
  213. <div class="span10 offset1 center" style="cursor: pointer" data-bind="visible: $root.roles().length == 0 && ! $root.isLoadingRoles(), click: function(){ if ($root.is_sentry_admin) { $root.showCreateRole(true); $('#createRoleModal').modal('show'); } }">
  214. <i class="fa fa-plus-circle waiting"></i>
  215. <h1 class="emptyMessage">
  216. ${ _('There are currently no roles defined') }<br/>
  217. <a class="pointer" data-bind="visible: $root.is_sentry_admin">${ _('Click here to add one') }</a>
  218. </h1>
  219. </div>
  220. <div class="clearfix" data-bind="visible: $root.roles().length == 0 && ! $root.isLoadingRoles()"></div>
  221. <div data-bind="visible: $root.roles().length > 0 && ! $root.isLoadingRoles()">
  222. <%actionbar:render>
  223. <%def name="search()">
  224. <input id="filterInput" type="text" class="input-xlarge search-query" placeholder="${_('Search roles by name, groups, etc...')}" data-bind="value: $root.roleFilter, valueUpdate: 'afterkeydown'">
  225. </%def>
  226. <%def name="actions()">
  227. <button class="btn toolbarBtn" data-bind="click: $root.expandSelectedRoles, enable: $root.selectedRoles().length > 0"><i class="fa fa-expand"></i> ${ _('Expand') }</button>
  228. <button class="btn toolbarBtn" data-bind="visible: $root.is_sentry_admin, click: function(){ $('#deleteRoleModal').modal('show'); }, enable: $root.selectedRoles().length > 0">
  229. <i class="fa fa-times"></i> ${ _('Delete') }
  230. </button>
  231. </%def>
  232. <%def name="creation()">
  233. <a data-bind="visible: $root.is_sentry_admin, click: function(){ $root.showCreateRole(true); $('#createRoleModal').modal('show'); }" class="btn pointer">
  234. <i class="fa fa-plus-circle"></i> ${ _('Add') }
  235. </a>
  236. </%def>
  237. </%actionbar:render>
  238. </div>
  239. <table class="card-marginbottom" data-bind="visible: $root.roles().length > 0 && ! $root.isLoadingRoles()">
  240. <thead>
  241. <th width="1%"><div data-bind="click: $root.selectAllRoles, css: { hueCheckbox: true, 'fa': true, 'fa-check': allRolesSelected }"></div></th>
  242. <th width="2%"></th>
  243. <th width="20%" style="text-align:left">${ _('Name') }</th>
  244. <th width="74%" style="text-align:left">${ _('Groups') }</th>
  245. <th width="3%"></th>
  246. </thead>
  247. <tbody data-bind="foreach: $root.filteredRoles">
  248. <tr>
  249. <td class="center" data-bind="click: handleSelect" style="cursor: default">
  250. <div data-bind="css: { hueCheckbox: true, 'fa': true, 'fa-check': selected }"></div>
  251. </td>
  252. <td class="center">
  253. <a href="javascript:void(0);" title="${ _('Show privileges') }">
  254. <i class="fa fa-2x fa-caret" data-bind="click: function() { if (showPrivileges()) { showPrivileges(false); } else { $root.list_sentry_privileges_by_role($data);} }, css: {'fa-caret-right' : ! showPrivileges(), 'fa-caret-down': showPrivileges() }"></i>
  255. </a>
  256. </td>
  257. <td data-bind="click: function() { if (showPrivileges()) { showPrivileges(false); } else { $root.list_sentry_privileges_by_role($data);} }" class="pointer">
  258. <a data-bind="attr: {'href': name}"></a>
  259. <i class="fa fa-cube muted"></i>
  260. <span data-bind="text: name"/>
  261. </td>
  262. <td>
  263. <a class="pointer" data-bind="click: function() { if ($root.is_sentry_admin) { showEditGroups(true); } }">
  264. <span data-bind="foreach: groups, visible: ! showEditGroups() && ! groupsChanged()">
  265. <span data-bind="text: $data"></span>
  266. </span>
  267. <span data-bind="visible: ! showEditGroups() && ! groupsChanged() && groups().length == 0">
  268. <i class="fa fa-plus"></i> ${ _('Add a group') }
  269. </span>
  270. </a>
  271. <div data-bind="visible: showEditGroups() || groupsChanged()">
  272. <select data-bind="options: $root.selectableHadoopGroups, selectedOptions: groups, select2: { update: groups, type: 'group'}" size="5" multiple="true" style="width: 400px"></select>
  273. &nbsp;
  274. <a class="pointer" data-bind="visible: groupsChanged, click: resetGroups">
  275. <i class="fa fa-undo"></i>
  276. </a>
  277. <a class="pointer" data-bind="visible: groupsChanged, click: saveGroups">
  278. <i class="fa fa-save"></i>
  279. </a>
  280. </div>
  281. </td>
  282. <td>
  283. </td>
  284. </tr>
  285. <tr>
  286. <td colspan="2"></td>
  287. <td colspan="4">
  288. <div data-bind="template: { name: 'privilege', foreach: $data.privileges }, visible: $data.showPrivileges">
  289. </div>
  290. </td>
  291. </tr>
  292. <tr data-bind="visible: $data.showPrivileges">
  293. <td colspan="2"></td>
  294. <td colspan="4">
  295. <div class="acl-block acl-actions" data-bind="click: privilegesChanged().length == 0 ? addPrivilege : void(0)">
  296. <span class="pointer" data-bind="click: addPrivilege, visible: $data.showPrivileges" title="${ _('Add privilege') }"><i class="fa fa-plus"></i></span>
  297. <span class="pointer" data-bind="click: $root.list_sentry_privileges_by_role, visible: privilegesChanged().length > 0" title="${ _('Undo') }"> &nbsp; <i class="fa fa-undo"></i></span>
  298. <span class="pointer" data-bind="click: function() { deletePrivilegeModal($data) }, visible: privilegesChanged().length > 0" title="${ _('Save') }"> &nbsp; <i class="fa fa-save"></i></span>
  299. </div>
  300. </td>
  301. </tr>
  302. </tbody>
  303. </table>
  304. </div>
  305. </div>
  306. </div> <!-- /span10 -->
  307. </div>
  308. <div id="createRoleModal" class="modal hide fade in" role="dialog">
  309. <div class="modal-header">
  310. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
  311. <h3 data-bind="visible: ! $root.role().isEditing()">${ _('Add role') }</h3>
  312. <h3 data-bind="visible: $root.role().isEditing()">${ _('Edit role') }</h3>
  313. </div>
  314. <div class="modal-body" data-bind="with: $root.role, visible: showCreateRole">
  315. <div class="row-fluid">
  316. <div class="span6">
  317. <h4>${ _('Name') }</h4>
  318. <input id="createRoleName" type="text" class="input-xlarge" data-bind="value: $data.name, visible: ! $data.isEditing()" placeholder="${ _('Required') }" style="width: 360px" />
  319. <strong data-bind="text: $data.name, visible: $data.isEditing()"></strong>
  320. </div>
  321. <div class="span6">
  322. <h4>${ _('Groups') }</h4>
  323. <select data-bind="options: $root.selectableHadoopGroups, selectedOptions: groups, select2: { update: groups, type: 'group', placeholder: '${ _("Optional") }' }" size="5" multiple="true" style="width: 360px"></select>
  324. </div>
  325. </div>
  326. <h4>${ _('Privileges') }</h4>
  327. <div data-bind="template: { name: 'privilege', foreach: privileges }"></div>
  328. <div class="acl-block acl-actions pointer" data-bind="click: addPrivilege">
  329. <span class="pointer" title="${ _('Add privilege') }"><i class="fa fa-plus"></i></span>
  330. </div>
  331. </div>
  332. <div class="modal-footer">
  333. <button class="btn" data-dismiss="modal" aria-hidden="true">${ _('Cancel') }</button>
  334. <button data-loading-text="${ _('Saving...') }" class="btn btn-primary disable-enter" data-bind="click: $root.role().create, visible: ! $root.role().isEditing()">${ _('Save') }</button>
  335. <button data-loading-text="${ _('Saving...') }" class="btn btn-primary disable-enter" data-bind="click: $root.role().update, visible: $root.role().isEditing()">${ _('Update') }</button>
  336. </div>
  337. </div>
  338. <div id="grantPrivilegeModal" class="modal hide fade in" role="dialog">
  339. <div class="modal-header">
  340. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
  341. <h3>${ _('Grant privilege') }</h3>
  342. </div>
  343. <div class="modal-body">
  344. <!-- ko if: $root.grantToPrivilege() -->
  345. <div data-bind="template: { name: 'privilege', data: $root.grantToPrivilege() }"></div>
  346. <!-- /ko -->
  347. <h4>${ _('To') }</h4>
  348. <select data-bind="options: $root.selectableRoles(), value: $root.grantToPrivilegeRole, select2: { update: $root.grantToPrivilegeRole, placeholder: '${ _("Select a role") }' }" style="width: 360px"></select>
  349. </br>
  350. </div>
  351. <div class="modal-footer">
  352. <button class="btn" data-dismiss="modal" aria-hidden="true">${ _('Cancel') }</button>
  353. <button data-loading-text="${ _('Saving...') }" class="btn btn-primary disable-enter" data-bind="click: $root.grant_privilege">${ _('Grant') }</button>
  354. </div>
  355. </div>
  356. <div id="deleteRoleModal" class="modal hide fade in" role="dialog">
  357. <div class="modal-header">
  358. <a href="#" class="close" data-dismiss="modal">&times;</a>
  359. <h3>${ _('Do you really want to delete the selected role(s)?') }</h3>
  360. </div>
  361. <div class="modal-footer">
  362. <button class="btn" data-dismiss="modal" aria-hidden="true">${ _('Cancel') }</button>
  363. <button data-loading-text="${ _('Deleting...') }" class="btn btn-danger" data-bind="click: $root.deleteSelectedRoles">${ _('Yes') }</button>
  364. </div>
  365. </div>
  366. <div id="deletePrivilegeModal" class="modal hide fade in" role="dialog">
  367. <div class="modal-header">
  368. <a href="#" class="close" data-dismiss="modal">&times;</a>
  369. <h3>${ _('Confirm the deletion?') }</h3>
  370. </div>
  371. <div class="modal-body">
  372. ${ _('Sentry will recursively delete the SERVER or DATABASE privileges you marked for deletion.') }
  373. </div>
  374. <div class="modal-footer">
  375. <button class="btn" data-dismiss="modal" aria-hidden="true">${ _('Cancel') }</button>
  376. <button data-loading-text="${ _('Deleting...') }" class="btn btn-danger" data-bind="click: function() { $root.role().savePrivileges($root.roleToUpdate()); }">${ _('Yes delete') }</button>
  377. </div>
  378. </div>
  379. <div id="bulkActionsModal" class="modal hide fade in" role="dialog">
  380. <div class="modal-header">
  381. <a href="#" class="close" data-dismiss="modal">&times;</a>
  382. <h3>${ _('Select one operation') }</h3>
  383. </div>
  384. <div class="modal-body" style="overflow-x: hidden">
  385. <div class="row-fluid">
  386. <div class="span8">
  387. <div class="row-fluid">
  388. <div class="span4 center">
  389. <div class="big-btn" data-bind="css: {'selected': $root.bulkAction() == 'add'}, click: function(){$root.bulkAction('add')}">
  390. <i class="fa fa-plus"></i><br/><br/>
  391. <span>${ _('Add current privileges to selection') }</span>
  392. </div>
  393. </div>
  394. <div class="span4 center">
  395. <div class="big-btn" data-bind="css: {'selected': $root.bulkAction() == 'sync'}, click: function(){$root.bulkAction('sync')}">
  396. <i class="fa fa-random"></i><br/><br/>
  397. <span>${ _('Replace selection with current privileges') }</span>
  398. </div>
  399. </div>
  400. <div class="span4 center">
  401. <div class="big-btn" data-bind="css: {'selected': $root.bulkAction() == 'delete'}, click: function(){$root.bulkAction('delete')}">
  402. <i class="fa fa-eraser"></i><br/><br/>
  403. <span>${ _('Delete all privileges of selection') }</span>
  404. </div>
  405. </div>
  406. </div>
  407. </div>
  408. <div class="span4">
  409. <h4>${ _('to apply to the selection') }</h4>
  410. <ul class="unstyled modal-panel" data-bind="foreach: $root.assist.checkedItems">
  411. <li data-bind="visible: path.indexOf('.') > -1" class="force-word-break">
  412. <i class="fa fa-database muted"></i>
  413. <span data-bind="text: path.split('.')[0]"></span>
  414. <i class="fa fa-long-arrow-right muted"></i>
  415. <i class="fa fa-table muted"></i>
  416. <span data-bind="text: path.split('.')[1]"></span>
  417. </li>
  418. <li data-bind="visible: path.indexOf('.') == -1" class="force-word-break">
  419. <i class="fa fa-database muted"></i> <span data-bind="text: path.split('.')[0]"></span>
  420. </li>
  421. </ul>
  422. </div>
  423. </div>
  424. <br/>
  425. <div class="row-fluid" data-bind="visible: $root.bulkAction() != '' && $root.bulkAction() != 'delete'">
  426. <div class="span12">
  427. <h4>${ _('Privileges to apply') }</h4>
  428. <div data-bind="visible: $root.assist.privileges().length == 0"><em class="muted">${ _('No privileges found for the selected item.')}</em></div>
  429. <div data-bind="template: { name: 'role', foreach: $root.assist.roles }" class="modal-panel"></div>
  430. </div>
  431. </div>
  432. </div>
  433. <div class="modal-footer">
  434. <button class="btn" data-dismiss="modal" aria-hidden="true">${ _('Cancel') }</button>
  435. <button class="btn" data-bind="enable: $root.bulkAction(), css: {'btn-primary': $root.bulkAction() != 'delete', 'btn-danger': $root.bulkAction() == 'delete'}, click: $root.bulkPerfomAction">${ _('Confirm') }</button>
  436. </div>
  437. </div>
  438. <div id="chooseFile" class="modal hide fade">
  439. <div class="modal-header">
  440. <a href="#" class="close" data-dismiss="modal">&times;</a>
  441. <h3>${_('Choose a file')}</h3>
  442. </div>
  443. <div class="modal-body">
  444. <div id="filechooser">
  445. </div>
  446. </div>
  447. <div class="modal-footer">
  448. </div>
  449. </div>
  450. <%def name="treeIcons()">
  451. 'fa-hdd-o': isServer(),
  452. 'fa-database-open': isDb() && (nodes().length > 0 || isLoaded()),
  453. 'fa-database': isDb() && nodes().length == 0,
  454. 'fa-table': isTable(),
  455. 'fa-columns': isColumn()
  456. </%def>
  457. <%def name="withPrivilegesPullRight()">
  458. <div class="pull-right">
  459. <i class="fa fa-shield" data-bind="visible: withPrivileges()" style="color: #338bb8" title="${ _('Has some privileges') }"></i>&nbsp;
  460. <i class="fa fa-file-o muted" data-bind="click: $root.assist.showHdfs ,visible: isTable()"></i>
  461. </div>
  462. </%def>
  463. ${ tree.import_templates(itemClick='$root.assist.setPath', iconClick='$root.assist.togglePath', itemSelected='$root.assist.path() == path()', styleModifier='withPrivileges', iconModifier=treeIcons, anchorProperty='path', itemChecked='isChecked', styleModifierPullRight=withPrivilegesPullRight) }
  464. <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
  465. <script src="/static/ext/js/knockout.mapping-2.3.2.js" type="text/javascript" charset="utf-8"></script>
  466. <script src="/static/ext/js/routie-0.3.0.min.js" type="text/javascript" charset="utf-8"></script>
  467. <script src="/security/static/js/common.ko.js" type="text/javascript" charset="utf-8"></script>
  468. <script src="/security/static/js/hive.ko.js" type="text/javascript" charset="utf-8"></script>
  469. <script src="/static/ext/js/moment.min.js" type="text/javascript" charset="utf-8"></script>
  470. <script src="/static/js/jquery.hiveautocomplete.js" type="text/javascript" charset="utf-8"></script>
  471. <script src="/static/js/jquery.filechooser.js" type="text/javascript" charset="utf-8"></script>
  472. <script type="text/javascript" charset="utf-8">
  473. function deletePrivilegeModal(role) {
  474. var cascadeDeletes = $.grep(role.privilegesChanged(), function(privilege) {
  475. return privilege.status() == 'deleted' && (privilege.privilegeScope() == 'SERVER' || privilege.privilegeScope() == 'DATABASE'); }
  476. );
  477. if (cascadeDeletes.length > 0 ) {
  478. viewModel.roleToUpdate(role);
  479. $('#deletePrivilegeModal').modal('show');
  480. } else {
  481. viewModel.role().savePrivileges(role);
  482. }
  483. }
  484. var viewModel = new HiveViewModel(${ initial | n,unicode });
  485. ko.applyBindings(viewModel);
  486. $(document).ready(function () {
  487. var _initialPath = viewModel.getPathHash();
  488. viewModel.init(_initialPath);
  489. $("#path").val(_initialPath);
  490. function setPathFromAutocomplete(path){
  491. if (path.lastIndexOf(".") == path.length -1){
  492. path = path.substring(0, path.length - 1);
  493. }
  494. viewModel.assist.path(path);
  495. viewModel.assist.updatePathProperty(viewModel.assist.growingTree(), path, "isExpanded", true);
  496. viewModel.assist.fetchHivePath();
  497. }
  498. $("#path").jHueHiveAutocomplete({
  499. skipColumns: true,
  500. home: viewModel.assist.path(),
  501. onPathChange: function (path) {
  502. setPathFromAutocomplete(path);
  503. },
  504. onEnter: function (el) {
  505. setPathFromAutocomplete(el.val());
  506. },
  507. smartTooltip: "${_('Did you know? You can use the tab key or CTRL + Space to autocomplete file and folder names')}"
  508. });
  509. function resizeComponents() {
  510. $("#path").width($(".tree-toolbar").width() - 64);
  511. $("#expandableTree").height($(window).height() - 260);
  512. $(".acl-panel-content").height($(window).height() - 240);
  513. }
  514. resizeComponents();
  515. $(document).on("rendered.tree", function() {
  516. var _path = viewModel.assist.path();
  517. if (_path[_path.length-1] == "/"){
  518. _path = _path.substr(0, _path.length - 1);
  519. }
  520. if ($("a.anchor[href^='"+_path+"']").length > 0){
  521. $("#expandableTree").animate({
  522. scrollTop: ($("a.anchor[href^='"+_path+"']:first").position().top + $("#expandableTree").scrollTop() - $("#expandableTree").position().top - 4) + "px"
  523. });
  524. }
  525. });
  526. $(document).on("created.role", function(){
  527. $("#createRoleModal").modal("hide");
  528. $("#grantPrivilegeModal").modal("hide");
  529. $("#deletePrivilegeModal").modal("hide");
  530. window.setTimeout(function(){
  531. viewModel.refreshExpandedRoles();
  532. }, 500);
  533. });
  534. $(document).on("deleted.role", function(){
  535. $("#deleteRoleModal").modal("hide");
  536. });
  537. $(document).on("changed.path", function(){
  538. if ($("#path").val() != viewModel.assist.path()){
  539. $("#path").val(viewModel.assist.path());
  540. }
  541. });
  542. function showMainSection(mainSection) {
  543. if ($("#" + mainSection).is(":hidden")) {
  544. $(".mainSection").hide();
  545. $("#" + mainSection).show();
  546. highlightMainMenu(mainSection);
  547. viewModel.updateSectionHash(mainSection);
  548. }
  549. logGA(mainSection);
  550. }
  551. function highlightMainMenu(mainSection) {
  552. $(".nav.nav-list li").removeClass("active");
  553. $("a[data-toggleSection='" + mainSection + "']").parent().addClass("active");
  554. }
  555. $("[data-toggleSection]").on("click", function(){
  556. showMainSection($(this).attr("data-toggleSection"));
  557. });
  558. showMainSection(viewModel.getSectionHash());
  559. $(document).on("show.role", function(e, role) {
  560. if (typeof role != "undefined" && role.name != null){
  561. $("#bulkActionsModal").modal("hide");
  562. showMainSection("roles");
  563. $("html, body").animate({
  564. scrollTop: ($("a[href='" + role.name() + "']").position().top - 90) + "px"
  565. });
  566. }
  567. });
  568. var _resizeTimeout = -1;
  569. $(window).resize(function(){
  570. window.clearTimeout(_resizeTimeout);
  571. _resizeTimeout = window.setTimeout(resizeComponents, 100);
  572. });
  573. window.onpopstate = function() {
  574. viewModel.assist.path(viewModel.getPathHash());
  575. };
  576. $("#createRoleModal").modal({
  577. show: false
  578. });
  579. $("#grantPrivilegeModal").modal({
  580. show: false
  581. });
  582. $("#createRoleModal").on("hidden", function () {
  583. $('#jHueHiveAutocomplete').hide();
  584. viewModel.resetCreateRole();
  585. });
  586. $("#deleteRoleModal").modal({
  587. show: false
  588. });
  589. $("#selectedGroup").select2("val", "");
  590. $("#selectedGroup").change(function() {
  591. viewModel.list_sentry_privileges_by_authorizable();
  592. viewModel.list_sentry_roles_by_group();
  593. });
  594. $(document).on("added.bulk.privileges", function() {
  595. $(document).trigger("info", "${ _('The current privileges have been successfully added to the checked items.') }");
  596. $("#bulkActionsModal").modal("hide");
  597. });
  598. $(document).on("deleted.bulk.privileges", function() {
  599. $(document).trigger("info", "${ _('All the privileges have been successfully removed from the checked items.') }");
  600. $("#bulkActionsModal").modal("hide");
  601. });
  602. $(document).on("syncd.bulk.privileges", function() {
  603. $(document).trigger("info", "${ _('All the privileges for the checked items have been replaced with the current selection.') }");
  604. $("#bulkActionsModal").modal("hide");
  605. });
  606. $("#bulkActionsModal").modal({
  607. show: false
  608. });
  609. $("#bulkActionsModal").on("hidden", function(){
  610. viewModel.isApplyingBulk(false);
  611. });
  612. $(document).on("create.typeahead", function(){
  613. $("#createRoleName").typeahead({
  614. source: function (query) {
  615. var _options = [];
  616. viewModel.selectableRoles().forEach(function(item){
  617. if (item.toLowerCase().indexOf(query.toLowerCase()) > -1){
  618. _options.push(item);
  619. }
  620. });
  621. return _options;
  622. },
  623. 'updater': function(item) {
  624. return item;
  625. }
  626. });
  627. });
  628. $(document).on("destroy.typeahead", function(){
  629. $('.typeahead').unbind();
  630. $("ul.typeahead").hide();
  631. });
  632. $(document).trigger("create.typeahead");
  633. $("#deletePrivilegeModal").modal({
  634. show: false
  635. });
  636. });
  637. </script>
  638. ${ commonfooter(messages) | n,unicode }