admin-ui.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <?php
  2. /**
  3. * Provides the core admin UI (Tools > Keyring) which includes:
  4. * - managing Service credentials
  5. * - creating connections
  6. * - deleting connections
  7. * - (coming soon) managing active/inactive Services
  8. *
  9. * Run Keyring with KEYRING__HEADLESS_MODE defined as true to disable all UI.
  10. *
  11. * @package Keyring
  12. */
  13. class Keyring_Admin_UI {
  14. var $keyring = false;
  15. function __construct() {
  16. add_action( 'admin_menu', array( $this, 'admin_menu' ) );
  17. }
  18. static function &init() {
  19. static $instance = false;
  20. if ( !$instance ) {
  21. $instance = new Keyring_Admin_UI;
  22. }
  23. return $instance;
  24. }
  25. function inline_css() {
  26. ?><style type="text/css">
  27. .wrap ul li {
  28. list-style-type: square;
  29. margin: .3em 0 .3em 2em;
  30. }
  31. </style><?php
  32. }
  33. function admin_menu() {
  34. $hook = add_management_page( 'Keyring', 'Keyring', 'read', 'keyring', array( $this, 'admin_page' ), '' );
  35. add_action( "load-$hook", array( $this, 'admin_page_load' ) );
  36. }
  37. function admin_page_load() {
  38. $this->keyring = Keyring::init();
  39. add_action( 'admin_head', array( $this, 'inline_css' ) );
  40. }
  41. function admin_page_header( $screen = false ) {
  42. // Output the actual heading + icon for the page
  43. echo '<div class="wrap">';
  44. screen_icon( 'ms-admin' );
  45. switch ( $screen ) {
  46. case 'tokens' :
  47. echo '<h2>' . __( 'Keyring: Managed Connections', 'keyring' ) . ' <a href="' . Keyring_Util::admin_url( false, array( 'action' => 'services' ) ) . '" class="add-new-h2">' . __( 'Add New', 'keyring' ) . '</a></h2>';
  48. break;
  49. case 'services' :
  50. echo '<h2>' . __( 'Add New Connection', 'keyring' ) . '</h2>';
  51. echo '<p><a href="' . Keyring_Util::admin_url() . '">' . __( '&larr; Back', 'keyring' ) . '</a></p>';
  52. break;
  53. case 'error' :
  54. echo '<h2>' . __( 'Keyring Error!', 'keyring' ) . '</h2>';
  55. break;
  56. default :
  57. echo '<h2>' . __( 'Keyring', 'keyring' ) . '</h2>';
  58. }
  59. // Output any errors if we have them, then stop, and link back to home.
  60. if ( $this->keyring->has_errors() ) {
  61. echo '<div id="keyring-admin-errors" class="updated"><ul>';
  62. foreach ( $this->keyring->get_errors() as $error ) {
  63. echo "<li>" . esc_html( $error ) . "</li>";
  64. }
  65. echo '</ul></div>';
  66. echo '<p class="submit"><a href="' . Keyring_Util::admin_url( $_REQUEST['service'] ) . '" class="button-primary">' . __( 'Start Again', 'keyring' ) . '</a></p>';
  67. return;
  68. }
  69. // Output any messages as part of the UI (don't abort).
  70. if ( $this->keyring->has_messages() ) {
  71. echo '<div id="keyring-admin-messages" class="updated"><ul>';
  72. foreach ( $this->keyring->get_messages() as $message ) {
  73. echo "<li>" . esc_html( $message ) . "</li>";
  74. }
  75. echo '</ul></div>';
  76. }
  77. }
  78. static function admin_page_footer() {
  79. echo '</div>'; // class="wrap"
  80. }
  81. function admin_page() {
  82. // Handle delete request. Will default back to "tokens" later
  83. if ( isset( $_REQUEST['action'] ) && 'delete' == $_REQUEST['action'] ) {
  84. if ( !isset( $_REQUEST['nonce'] ) || !wp_verify_nonce( $_REQUEST['nonce'], 'keyring-delete-' . $_REQUEST['service'] . '-' . $_REQUEST['token'] ) ) {
  85. Keyring::error( __( 'Invalid/missing delete nonce.', 'keyring' ) );
  86. exit;
  87. }
  88. if ( $this->keyring->get_token_store()->delete( array( 'id' => (int) $_REQUEST['token'], 'type' => 'access' ) ) )
  89. Keyring::message( __( 'That connection has been deleted.', 'keyring' ) );
  90. else
  91. Keyring::message( __( 'Could not delete that connection!', 'keyring' ) );
  92. }
  93. // Set up our defaults
  94. $service = '';
  95. if ( !empty( $_REQUEST['service'] ) )
  96. $service = $_REQUEST['service'];
  97. $action = 'tokens';
  98. if ( isset( $_REQUEST['action'] ) && in_array( $_REQUEST['action'], array( 'tokens', 'services', 'request', 'verify', 'manage' ) ) )
  99. $action = $_REQUEST['action'];
  100. // Custom UI optionally hooked in to handle this service/action. Trigger action
  101. // and assume it handles everything, so bail out after that.
  102. if ( Keyring_Util::has_custom_ui( $service, $action ) ) {
  103. do_action( "keyring_{$service}_{$action}_ui" );
  104. return;
  105. }
  106. // Nothing else has bailed, so it must be one of our default/core screens.
  107. switch ( $action ) {
  108. case 'tokens' :
  109. $this->admin_page_header( 'tokens' );
  110. $list_table = new Keyring_Connections_List_Table();
  111. $list_table->display();
  112. $this->admin_page_footer();
  113. break;
  114. case 'services' :
  115. $this->admin_page_header( 'services' );
  116. $services = $this->keyring->get_registered_services();
  117. if ( count( $services ) ) {
  118. $configured = $not_configured = array();
  119. foreach ( $services as $service ) {
  120. if ( $service->is_configured() )
  121. $configured[] = $service;
  122. else
  123. $not_configured[] = $service;
  124. }
  125. if ( count( $configured ) ) {
  126. echo '<p><strong>' . __( 'Click a service to create a new connection:', 'keyring' ) . '</strong></p>';
  127. echo '<ul>';
  128. foreach ( $configured as $service ) {
  129. $request_kr_nonce = wp_create_nonce( 'keyring-request' );
  130. $request_nonce = wp_create_nonce( 'keyring-request-' . $service->get_name() );
  131. echo '<li><a href="' . esc_url( Keyring_Util::admin_url( $service->get_name(), array( 'action' => 'request', 'kr_nonce' => $request_kr_nonce, 'nonce' => $request_nonce ) ) ) . '">' . esc_html( $service->get_label() ) . '</a>';
  132. if ( has_action( 'keyring_' . $service->get_name() . '_manage_ui' ) ) {
  133. $manage_kr_nonce = wp_create_nonce( 'keyring-manage' );
  134. $manage_nonce = wp_create_nonce( 'keyring-manage-' . $service->get_name() );
  135. echo ' (<a href="' . esc_url( Keyring_Util::admin_url( $service->get_name(), array( 'action' => 'manage', 'kr_nonce' => $manage_kr_nonce, 'nonce' => $manage_nonce ) ) ) . '">' . esc_html( __( 'Manage', 'keyring' ) ) . '</a>)';
  136. }
  137. echo '</li>';
  138. }
  139. echo '</ul><br /><br />';
  140. } else {
  141. echo '<p>' . __( 'There are no fully-configured services available to connect to.', 'keyring' ) . '</p>';
  142. }
  143. if ( count( $not_configured ) ) {
  144. echo '<p>' . __( 'The following services need to be configured correctly before you can connect to them.', 'keyring' ) . '</p>';
  145. echo '<ul>';
  146. foreach ( $not_configured as $service ) {
  147. if ( !has_action( 'keyring_' . $service->get_name() . '_manage_ui' ) )
  148. continue;
  149. $manage_kr_nonce = wp_create_nonce( 'keyring-manage' );
  150. $manage_nonce = wp_create_nonce( 'keyring-manage-' . $service->get_name() );
  151. echo '<li><a href="' . esc_url( Keyring_Util::admin_url( $service->get_name(), array( 'action' => 'manage', 'kr_nonce' => $manage_kr_nonce, 'nonce' => $manage_nonce ) ) ) . '">' . esc_html( $service->get_label() ) . '</a></li>';
  152. }
  153. echo '</ul>';
  154. }
  155. }
  156. $this->admin_page_footer();
  157. break;
  158. }
  159. }
  160. }
  161. /** WordPress List Table Administration API and base class */
  162. require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
  163. class Keyring_Connections_List_Table extends WP_List_Table {
  164. var $keyring = false;
  165. function __construct() {
  166. $this->keyring = Keyring::init();
  167. parent::__construct( array(
  168. 'singular' => 'connection',
  169. 'plural' => 'connections',
  170. 'screen' => $this->keyring->admin_page,
  171. ) );
  172. $this->items = Keyring::get_token_store()->get_tokens();
  173. }
  174. function no_items() {
  175. echo '<p>' . sprintf( __( 'You haven\'t added any connections yet. <a href="%s">Add a New Connection</a>.', 'keyring' ), esc_url( Keyring_Util::admin_url( false, array( 'action' => 'services' ) ) ) ) . '</p>';
  176. }
  177. function get_columns() {
  178. return array(
  179. 'service' => __( 'Service', 'keyring' ),
  180. 'avatar' => __( 'Avatar', 'keyring' ),
  181. 'id' => __( 'External ID', 'keyring' ),
  182. 'name' => __( 'Name', 'keyring' ),
  183. 'actions' => '&nbsp;'
  184. );
  185. }
  186. function column_service( $row ) {
  187. echo $row->get_service()->get_label();
  188. }
  189. function column_avatar( $row ) {
  190. $picture = $row->get_meta( 'picture' );
  191. if ( $picture ) {
  192. echo '<img src="' . esc_attr( $picture ) . '" width="40" height="40" border="1" alt="' . __( 'Avatar', 'keyring' ) . '" />';
  193. } else {
  194. echo '-';
  195. }
  196. }
  197. function column_id( $row ) {
  198. echo $row->get_meta( 'user_id' );
  199. }
  200. function column_name( $row ) {
  201. // Make a few attempts to get something to display here
  202. $name = $row->get_meta( 'name' );
  203. if ( !$name )
  204. $name = $row->get_meta( 'username' );
  205. if ( !$name )
  206. $name = trim( $row->get_meta( 'first_name' ) . ' ' . $row->get_meta( 'last_name' ) );
  207. if ( $name )
  208. echo $name;
  209. else
  210. echo '-';
  211. }
  212. function column_actions( $row ) {
  213. $kr_nonce = wp_create_nonce( 'keyring-delete' );
  214. $delete_nonce = wp_create_nonce( 'keyring-delete-' . $row->get_service()->get_name() . '-' . $row->get_uniq_id() );
  215. echo '<a href="' . Keyring_Util::admin_url( false, array( 'action' => 'delete', 'service' => $row->get_service()->get_name(), 'token' => $row->get_uniq_id(), 'kr_nonce' => $kr_nonce, 'nonce' => $delete_nonce ) ) . '" title="' . esc_attr( __( 'Delete', 'keyring' ) ) . '" class="delete">Delete</a>';
  216. }
  217. }