<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[4525] sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt: Mentor Dashboard: Use dotorg usernames to id mentors instead of email</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="http://meta.trac.wordpress.org/changeset/4525">4525</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://meta.trac.wordpress.org/changeset/4525","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>coreymckrill</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2016-12-13 20:45:19 +0000 (Tue, 13 Dec 2016)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Mentor Dashboard: Use dotorg usernames to id mentors instead of email

* Adds the `Mentor WordPress.org User Name` field to wcpt.
* Introduces "protected" fields in wcpt, which will be marked as
  readonly unless current user has specific caps. Used to make all
  mentor fields in the wcpt edit screen readonly unless current user
  can manage the network.
* Adds a dropdown pick list of current mentors next to
  `Mentor WordPress.org User Name` that will fill in username, name,
  and email when a mentor is chosen. This only appears if current user
  has the right caps.
* Adds a field in the Mentor Dashboard for managing the list of current
  mentors based on their dotorg usernames.
* Uses dotorg username to determine which camps a mentor currently has,
  with their dotorg account email address as a backup.
* All camps that don't have a value for `Mentor WordPress.org User Name`
  or whose value doesn't match a current mentor will appear in the
  "Active Camps that don't have a mentor" list.
* Enqueues existing admin.js script for wcpt instead of printing it in
  the footer.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptjavascriptwcptwordcampadminjs">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/javascript/wcpt-wordcamp/admin.js</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptmentorsdashboardphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/mentors/dashboard.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptviewsmentorsdashboardphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/dashboard.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptviewsmentorsmentorsphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/mentors.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptviewsmentorsunmentoredcampsphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/unmentored-camps.php</a></li>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptwcptwordcampwordcampadminphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/wcpt-wordcamp/wordcamp-admin.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptviewsmentorsmanagementorsphp">sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/manage-mentors.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptjavascriptwcptwordcampadminjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/javascript/wcpt-wordcamp/admin.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/javascript/wcpt-wordcamp/admin.js    2016-12-13 18:50:47 UTC (rev 4524)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/javascript/wcpt-wordcamp/admin.js      2016-12-13 20:45:19 UTC (rev 4525)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -9,16 +9,24 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Initialize
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        self.initialize = function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                var createSiteCheckbox = $( '#wcpt_create-site-in-network' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         var createSiteCheckbox = $( '#wcpt_create-site-in-network' ),
+                       $mentorUserName = $( '#wcpt_mentor_wordpress_org_user_name' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Sponsor region
</ins><span class="cx" style="display: block; padding: 0 10px">                 createSiteCheckbox.change( self.toggleSponsorRegionRequired );
</span><span class="cx" style="display: block; padding: 0 10px">                createSiteCheckbox.trigger( 'change' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Date fields
</ins><span class="cx" style="display: block; padding: 0 10px">                 $( '.date-field' ).datepicker( {
</span><span class="cx" style="display: block; padding: 0 10px">                        dateFormat: 'yy-mm-dd',
</span><span class="cx" style="display: block; padding: 0 10px">                        changeMonth: true,
</span><span class="cx" style="display: block; padding: 0 10px">                        changeYear:  true
</span><span class="cx" style="display: block; padding: 0 10px">                } );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               // Mentor username picker
+               if ( $mentorUserName.length && ! $mentorUserName.is( '[readonly]' ) ) {
+                       self.initializeMentorPicker( $mentorUserName );
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38,6 +46,72 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    /**
+        * Insert a Mentor picker after the Mentor username field.
+        *
+     * @param $el jQuery object for the Mentor username field.
+     */
+       self.initializeMentorPicker = function( $el ) {
+               if ( 'undefined' === typeof window.wordCampPostType.Mentors.data ) {
+                       return;
+               }
+
+               var data     = window.wordCampPostType.Mentors.data,
+                       l10n     = window.wordCampPostType.Mentors.l10n,
+                       $select  = $( '<select id="wcpt-mentor-picker"><option></option></select>' ),
+                       $wrapper = $( '<span class="description">' ),
+                       $label   = $( '<label>' ).text( l10n.selectLabel );
+
+               $.each( data, function( key, value ) {
+                       var $option = $( '<option>' );
+
+                       $option.val(key)
+                               .data({
+                                       name: value.name,
+                                       email: value.email
+                               })
+                               .text( value.name );
+
+                       if ( $option.val() === $el.val() ) {
+                               $option.prop( 'selected', 'selected' );
+                       }
+
+                       $select.append( $option );
+               });
+
+               $wrapper.append( $label )
+                       .append( $select )
+                       .insertAfter( $el );
+
+               // Bind events
+               $select.on( 'change', function() {
+                       var $option = $( this ).find( 'option:selected' );
+                       self.updateMentor( $option );
+               });
+       };
+
+    /**
+        * Update the Mentor fields with the data for the mentor chosen in the picker.
+        *
+     * @param $option jQuery object for the selected option element.
+     */
+       self.updateMentor = function( $option ) {
+               var l10n            = window.wordCampPostType.Mentors.l10n,
+                       $mentorUserName = $( '#wcpt_mentor_wordpress_org_user_name' ),
+                       $mentorName     = $( '#wcpt_mentor_name' ),
+                       $mentorEmail    = $( '#wcpt_mentor_e-mail_address' );
+
+               // Confirm before changing Mentor field contents
+               if ( $option.val() && confirm( l10n.confirm ) ) {
+            $mentorUserName.val( $option.val() );
+            $mentorName.val( $option.data('name') );
+            $mentorEmail.val( $option.data('email') );
+               }
+       };
+
+    /**
+        * Kick things off
+     */
</ins><span class="cx" style="display: block; padding: 0 10px">         $( document ).ready( function( $ ) {
</span><span class="cx" style="display: block; padding: 0 10px">                self.initialize();
</span><span class="cx" style="display: block; padding: 0 10px">        } );
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptmentorsdashboardphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/mentors/dashboard.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/mentors/dashboard.php        2016-12-13 18:50:47 UTC (rev 4524)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/mentors/dashboard.php  2016-12-13 20:45:19 UTC (rev 4525)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3,6 +3,26 @@
</span><span class="cx" style="display: block; padding: 0 10px"> namespace WordCamp\Mentors_Dashboard;
</span><span class="cx" style="display: block; padding: 0 10px"> defined( 'WPINC' ) or die();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+const USERNAMES_KEY     = 'wcpt-mentors-usernames';
+const MENTORS_CACHE_KEY = 'wcpt-mentors-data';
+
+const STATUS_UPDATED       = 'Mentor usernames updated.';
+const STATUS_INVALID_NONCE = 'Invalid nonce. Mentor usernames were not updated.';
+const STATUS_NO_USERNAME   = 'No username data was submitted.';
+const STATUS_UPDATE_FAILED = 'Mentor usernames could not be updated.';
+
+
+add_action( 'admin_init', __NAMESPACE__ . '\admin_init' );
+
+/**
+ * Initialize admin functionality
+ */
+function admin_init() {
+       if ( isset( $_GET['wcpt-status'] ) ) {
+               add_action( 'admin_notices', __NAMESPACE__ . '\status_admin_notice' );
+       }
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> add_action( 'admin_menu', __NAMESPACE__ . '\add_admin_pages' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -25,6 +45,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> function render_options_page() {
</span><span class="cx" style="display: block; padding: 0 10px">        $mentors          = get_mentors();
</span><span class="cx" style="display: block; padding: 0 10px">        $unmentored_camps = get_unmentored_camps();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $usernames        = get_usernames();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        require_once( dirname( __DIR__ ) . '/views/mentors/dashboard.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -35,43 +56,58 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @return array
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function get_mentors() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $mentors = array();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $mentors = get_all_mentor_data();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if ( empty( $mentors ) ) {
+               return array();
+       }
+
+       $mentor_email = wp_list_pluck( $mentors, 'email' );
+
+       $post_statuses = array_diff(
+               \WordCamp_Loader::get_mentored_post_statuses(),
+               array( 'wcpt-closed' )
+       );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         $mentored_camps = get_posts( array(
</span><span class="cx" style="display: block; padding: 0 10px">                'post_type'      => WCPT_POST_TYPE_ID,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                'post_status'    => \WordCamp_Loader::get_mentored_post_statuses(),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         'post_status'    => $post_statuses,
</ins><span class="cx" style="display: block; padding: 0 10px">                 'posts_per_page' => 10000,
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                'order'          => 'ASC',
+               'orderby'        => 'name',
</ins><span class="cx" style="display: block; padding: 0 10px">                 'meta_query'     => array(
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'relation' => 'OR',
</ins><span class="cx" style="display: block; padding: 0 10px">                         array(
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                'key'     => 'Mentor WordPress.org User Name',
+                               'value'   => get_usernames(),
+                               'compare' => 'IN',
+                       ),
+                       array(
</ins><span class="cx" style="display: block; padding: 0 10px">                                 'key'     => 'Mentor E-mail Address',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'value'   => '',
-                               'compare' => '!='
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'value'   => $mentor_email,
+                               'compare' => 'IN',
</ins><span class="cx" style="display: block; padding: 0 10px">                         ),
</span><span class="cx" style="display: block; padding: 0 10px">                ),
</span><span class="cx" style="display: block; padding: 0 10px">        ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $mentors = array_map( function( $value ) {
+               $value['camps_mentoring'] = array();
+               return $value;
+       }, $mentors );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         foreach ( $mentored_camps as $camp ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $email = get_post_meta( $camp->ID, 'Mentor E-mail Address', true );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $username = get_post_meta( $camp->ID, 'Mentor WordPress.org User Name', true );
+               $email    = get_post_meta( $camp->ID, 'Mentor E-mail Address', true );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                /*
-                * Closed camps were included in the query above, in order to get all mentors, even if they're not
-                * currently mentoring any active camps. Closed camps shouldn't be included in the list of camps being
-                * actively mentored, though.
-                */
-               $count_camp = 'wcpt-closed' !== $camp->post_status;
-
-               if ( array_key_exists( $email, $mentors ) ) {
-                       if ( $count_camp ) {
-                               $mentors[ $email ]['camps_mentoring'][] = $camp->post_title;
-                       }
-               } else {
-                       $mentor_name = get_post_meta( $camp->ID, 'Mentor Name', true );
-
-                       $mentors[ $email ] = array(
-                               'name'            => $mentor_name,
-                               'camps_mentoring' => $count_camp ? array( $camp->post_title ) : array(),
-                       );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Camp has username
+               if ( false !== $username && isset( $mentors[ $username ] ) ) {
+                       $mentors[ $username ]['camps_mentoring'][ $camp->ID ] = $camp->post_title;
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Camp doesn't have username, but has email
+               else if ( false !== $email && false !== $key = array_search( $email, $mentor_email ) ) {
+                       // Add asterisk to show camp has mentor email but not username
+                       $mentors[ $key ]['camps_mentoring'][ $camp->ID ] = $camp->post_title . ' *';
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        return $mentors;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -111,18 +147,205 @@
</span><span class="cx" style="display: block; padding: 0 10px">                'post_type'      => WCPT_POST_TYPE_ID,
</span><span class="cx" style="display: block; padding: 0 10px">                'post_status'    => $post_statuses,
</span><span class="cx" style="display: block; padding: 0 10px">                'posts_per_page' => 10000,
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                'order'          => 'ASC',
+               'orderby'        => 'name',
</ins><span class="cx" style="display: block; padding: 0 10px">                 'meta_query'     => array(
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'relation' => 'OR',
</ins><span class="cx" style="display: block; padding: 0 10px">                         array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'key'     => 'Mentor E-mail Address',
-                               'value'   => '',
-                               'compare' => '='
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'key'     => 'Mentor WordPress.org User Name',
+                               'value'   => get_usernames(),
+                               'compare' => 'NOT IN'
</ins><span class="cx" style="display: block; padding: 0 10px">                         ),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        array(
+                               'key'     => 'Mentor WordPress.org User Name',
+                               'compare' => 'NOT EXISTS'
+                       ),
</ins><span class="cx" style="display: block; padding: 0 10px">                 ),
</span><span class="cx" style="display: block; padding: 0 10px">        ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        foreach ( $posts as $post ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $unmentored_camps[ $post->ID ] = $post->post_title;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $email = get_post_meta( $post->ID, 'Mentor E-mail Address', true );
+               $camp_name = $post->post_title;
+
+               if ( $email ) {
+                       $camp_name .= ' *';
+               }
+
+               $unmentored_camps[ $post->ID ] = $camp_name;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        return $unmentored_camps;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+/**
+ * Get the stored array of mentor usernames and sanitize before returning.
+ *
+ * @return array
+ */
+function get_usernames() {
+       $raw_usernames = get_site_option( USERNAMES_KEY, array() );
+
+       return sanitize_usernames( $raw_usernames );
+}
+
+/**
+ * Sanitize a list of usernames and store in the database.
+ *
+ * @param string|array $usernames
+ *
+ * @return bool
+ */
+function set_usernames( $usernames ) {
+       $sanitized_usernames = sanitize_usernames( $usernames );
+
+       return update_site_option( USERNAMES_KEY, $sanitized_usernames );
+}
+
+/**
+ * Sanitize an array of usernames. Convert to an array first if a string is provided.
+ *
+ * @param string|array $usernames
+ *
+ * @return array
+ */
+function sanitize_usernames( $usernames ) {
+       if ( ! is_array( $usernames ) ) {
+               $usernames = explode( ',', $usernames );
+       }
+
+       $usernames = array_map( 'trim', $usernames );
+
+       $usernames = array_map( 'sanitize_user', $usernames );
+
+       // Remove empty array items
+       return array_filter( $usernames );
+}
+
+/**
+ * @todo
+ *
+ * @param array $sanitized_usernames
+ */
+function validate_usernames( array $sanitized_usernames ) {
+       // todo
+}
+
+add_action( 'admin_post_wcpt-mentors-update-usernames', __NAMESPACE__ . '\update_usernames' );
+
+/**
+ * Admin Post callback to receive a list of usernames from a form and store it in the database.
+ */
+function update_usernames() {
+       // Base redirect URL
+       $redirect_url = add_query_arg( array(
+               'post_type' => 'wordcamp',
+               'page'      => 'mentors',
+       ), admin_url( 'edit.php' ) );
+
+       // Invalid nonce
+       if ( ! isset( $_POST['wcpt-mentors-nonce'] ) ||
+                ! wp_verify_nonce( $_POST['wcpt-mentors-nonce'], 'wcpt-mentors-update-usernames' ) ) {
+               $status_code = 'invalid-nonce';
+       }
+       // No usernames field
+       else if ( ! isset( $_POST['wcpt-mentors-usernames'] ) ) {
+               $status_code = 'no-username';
+       }
+       //
+       else {
+               $raw_usernames = $_POST['wcpt-mentors-usernames'];
+
+               $success = set_usernames( $raw_usernames );
+
+               if ( $success ) {
+                       $status_code = 'updated';
+
+                       // Bust cache
+                       delete_site_transient( MENTORS_CACHE_KEY );
+               } else {
+                       $status_code = 'update-failed';
+               }
+       }
+
+       $redirect_url = add_query_arg( 'wcpt-status', $status_code, $redirect_url );
+
+       wp_safe_redirect( esc_url_raw( $redirect_url ) );
+}
+
+/**
+ * Display the result of `update_usernames`
+ */
+function status_admin_notice() {
+       if ( ! isset( $_GET['wcpt-status'] ) ) {
+               return;
+       }
+
+       $status = 'STATUS_' . strtoupper( str_replace( '-', '_', $_GET['wcpt-status'] ) );
+
+       if ( ! defined( __NAMESPACE__ . '\\' . $status ) ) {
+               return;
+       }
+
+       $type = 'success';
+       if ( 'STATUS_UPDATED' !== $status ) {
+               $type = 'error';
+       }
+
+       $message = constant( __NAMESPACE__ . '\\' . $status );
+
+       ?>
+       <div class="notice notice-<?php echo esc_attr( $type ); ?> is-dismissible">
+               <?php echo wpautop( esc_html( $message ) ); ?>
+       </div>
+<?php
+}
+
+/**
+ * Retrieve name and email for a particular mentor username.
+ *
+ * @param string $username
+ *
+ * @return array
+ */
+function get_mentor_data( $username ) {
+       $usernames = get_usernames();
+       $data = array();
+
+       // Data for specific mentor
+       if ( in_array( $username, $usernames ) ) {
+               $user = \get_user_by( 'login', $username );
+
+               if ( $user instanceof \WP_User ) {
+                       $data[ $username ] = array(
+                               'name'  => $user->display_name,
+                               'email' => $user->user_email,
+                       );
+               }
+       }
+
+       return $data;
+}
+
+/**
+ * Retrieve data for all the mentor usernames in the list.
+ *
+ * @return array
+ */
+function get_all_mentor_data() {
+       if ( false !== $data = \get_site_transient( MENTORS_CACHE_KEY ) ) {
+               return $data;
+       }
+
+       $usernames = get_usernames();
+       $data = array();
+
+       foreach ( $usernames as $username ) {
+               $data = array_merge( $data, get_mentor_data( $username ) );
+       }
+
+       ksort( $data );
+
+       \set_site_transient( MENTORS_CACHE_KEY, $data, WEEK_IN_SECONDS );
+
+       return $data;
+}
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptviewsmentorsdashboardphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/dashboard.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/dashboard.php  2016-12-13 18:50:47 UTC (rev 4524)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/dashboard.php    2016-12-13 20:45:19 UTC (rev 4525)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -11,11 +11,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <div class="wrap">
</span><span class="cx" style="display: block; padding: 0 10px">        <h1>WordCamp Mentors Dashboard</h1>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        <p class="description">
-               Note: This page doesn't include people who have agreed to be a mentor, but have never been assigned to a
-               camp.
-       </p>
-
</del><span class="cx" style="display: block; padding: 0 10px">         <ul>
</span><span class="cx" style="display: block; padding: 0 10px">                <li>Number of mentors:             <?php echo count( $mentors );                                ?></li>
</span><span class="cx" style="display: block; padding: 0 10px">                <li>Active camps being mentored:   <?php echo absint( count_camps_being_mentored( $mentors ) ); ?></li>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -24,4 +19,5 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <?php require_once( __DIR__ . '/mentors.php'          ); ?>
</span><span class="cx" style="display: block; padding: 0 10px">        <?php require_once( __DIR__ . '/unmentored-camps.php' ); ?>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <?php require_once( __DIR__ . '/manage-mentors.php' ); ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </div>
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptviewsmentorsmanagementorsphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/manage-mentors.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/manage-mentors.php                             (rev 0)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/manage-mentors.php       2016-12-13 20:45:19 UTC (rev 4525)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,21 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace WordCamp\Mentors_Dashboard;
+defined( 'WPINC' ) or die();
+
+/** @var array $usernames */
+
+?>
+
+<h2>Manage Mentor List</h2>
+
+<p class="description">Configure the list of currently active mentors. Enter WordPress.org usernames, separated by commas.</p>
+
+<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
+       <textarea class="widefat" name="wcpt-mentors-usernames"><?php echo implode( ',', $usernames ); ?></textarea>
+
+       <input type="hidden" name="action" value="wcpt-mentors-update-usernames" />
+       <?php wp_nonce_field( 'wcpt-mentors-update-usernames', 'wcpt-mentors-nonce' ); ?>
+
+       <p><input type="submit" class="button button-primary" value="Update" /></p>
+</form>
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptviewsmentorsmentorsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/mentors.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/mentors.php    2016-12-13 18:50:47 UTC (rev 4524)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/mentors.php      2016-12-13 20:45:19 UTC (rev 4525)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12,21 +12,27 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <table class="widefat fixed striped">
</span><span class="cx" style="display: block; padding: 0 10px">        <thead>
</span><span class="cx" style="display: block; padding: 0 10px">                <th>Mentor</th>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                <th>Username</th>
</ins><span class="cx" style="display: block; padding: 0 10px">                 <th>Email Address</th>
</span><span class="cx" style="display: block; padding: 0 10px">                <th># Currently Mentoring</th>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                <th>Currently Mentoring</th>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         <th>Camps</th>
</ins><span class="cx" style="display: block; padding: 0 10px">         </thead>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <tbody>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                <?php foreach ( $mentors as $email_address => $mentor ) : ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         <?php foreach ( $mentors as $username => $mentor ) : ?>
</ins><span class="cx" style="display: block; padding: 0 10px">                         <tr>
</span><span class="cx" style="display: block; padding: 0 10px">                                <td><?php echo esc_html( $mentor['name'] );         ?></td>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                <td><?php echo esc_html( $email_address );          ?></td>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         <td><?php echo esc_html( $username );               ?></td>
+                               <td><?php echo esc_html( $mentor['email'] );        ?></td>
</ins><span class="cx" style="display: block; padding: 0 10px">                                 <td><?php echo count( $mentor['camps_mentoring'] ); ?></td>
</span><span class="cx" style="display: block; padding: 0 10px">                                <td>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <ul>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                <?php foreach ( $mentor['camps_mentoring'] as $camp ) : ?>
-                                                       <li><?php echo esc_html( $camp ); ?></li>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         <?php foreach ( $mentor['camps_mentoring'] as $camp_id => $camp_name ) : ?>
+                                                       <li>
+                                                               <a href="<?php echo esc_url( admin_url( "post.php?post=$camp_id&action=edit#wcpt_mentor_wordpress_org_user_name" ) ); ?>">
+                                                                       <?php echo esc_html( $camp_name ); ?>
+                                                               </a>
+                                                       </li>
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 <?php endforeach; ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                        </ul>
</span><span class="cx" style="display: block; padding: 0 10px">                                </td>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -34,3 +40,5 @@
</span><span class="cx" style="display: block; padding: 0 10px">                <?php endforeach; ?>
</span><span class="cx" style="display: block; padding: 0 10px">        </tbody>
</span><span class="cx" style="display: block; padding: 0 10px"> </table>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+<p class="description">(*) Camp has a Mentor email address but not a WordPress.org username.</p>
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptviewsmentorsunmentoredcampsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/unmentored-camps.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/unmentored-camps.php   2016-12-13 18:50:47 UTC (rev 4524)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/views/mentors/unmentored-camps.php     2016-12-13 20:45:19 UTC (rev 4525)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -9,18 +9,22 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> <h2>Active Camps without a Mentor</h2>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<p class="description">Note: This is based on the <strong>Mentor WordPress.org User Name</strong> field. Some of these camps may have Mentor name and/or email data, but have not yet been updated with the WordPress.org username.</p>
+
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php if ( $unmentored_camps ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <ul class="ul-disc">
</span><span class="cx" style="display: block; padding: 0 10px">                <?php foreach ( $unmentored_camps as $id => $name ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px">                        <li>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                <a href="<?php echo esc_url( admin_url( "post.php?post=$id&action=edit" ) ); ?>">
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         <a href="<?php echo esc_url( admin_url( "post.php?post=$id&action=edit#wcpt_mentor_wordpress_org_user_name" ) ); ?>">
</ins><span class="cx" style="display: block; padding: 0 10px">                                         <?php echo esc_html( $name ); ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                </a>
</span><span class="cx" style="display: block; padding: 0 10px">                        </li>
</span><span class="cx" style="display: block; padding: 0 10px">                <?php endforeach; ?>
</span><span class="cx" style="display: block; padding: 0 10px">        </ul>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <p class="description">(*) Camp has a Mentor email address but no WordPress.org username.</p>
+
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php else : ?>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <p>All active camps have been assigned a mentor.</p>
</span></span></pre></div>
<a id="sitestrunkwordcamporgpublic_htmlwpcontentpluginswcptwcptwordcampwordcampadminphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/wcpt-wordcamp/wordcamp-admin.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/wcpt-wordcamp/wordcamp-admin.php     2016-12-13 18:50:47 UTC (rev 4524)
+++ sites/trunk/wordcamp.org/public_html/wp-content/plugins/wcpt/wcpt-wordcamp/wordcamp-admin.php       2016-12-13 20:45:19 UTC (rev 4525)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,5 +1,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use WordCamp\Mentors_Dashboard;
+
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( ! class_exists( 'WordCamp_Admin' ) ) :
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * WCPT_Admin
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -36,7 +38,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Scripts and CSS
</span><span class="cx" style="display: block; padding: 0 10px">                add_action( 'admin_enqueue_scripts',                          array( $this, 'admin_scripts' ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                add_action( 'admin_print_scripts',                            array( $this, 'admin_print_scripts' ), 99 );
</del><span class="cx" style="display: block; padding: 0 10px">                 add_action( 'admin_print_styles',                             array( $this, 'admin_styles' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                // Post status transitions
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -179,6 +180,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $post_value   = wcpt_key_to_str( $key, 'wcpt_' );
</span><span class="cx" style="display: block; padding: 0 10px">                        $values[ $key ] = isset( $_POST[ $post_value ] ) ? esc_attr( $_POST[ $post_value ] ) : '';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        // Don't update protected fields
+                       if ( self::is_protected_field( $key ) ) {
+                               continue;
+                       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         switch ( $value ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                case 'text'     :
</span><span class="cx" style="display: block; padding: 0 10px">                                case 'textarea' :
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -380,6 +386,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        'Travel Wrangler E-mail Address'                 => 'text',
</span><span class="cx" style="display: block; padding: 0 10px">                                        'Safety Wrangler Name'                           => 'text',
</span><span class="cx" style="display: block; padding: 0 10px">                                        'Safety Wrangler E-mail Address'                 => 'text',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                        'Mentor WordPress.org User Name'                 => 'text',
</ins><span class="cx" style="display: block; padding: 0 10px">                                         'Mentor Name'                                    => 'text',
</span><span class="cx" style="display: block; padding: 0 10px">                                        'Mentor E-mail Address'                          => 'text',
</span><span class="cx" style="display: block; padding: 0 10px">                                );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -460,6 +467,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        'Travel Wrangler E-mail Address'                 => 'text',
</span><span class="cx" style="display: block; padding: 0 10px">                                        'Safety Wrangler Name'                           => 'text',
</span><span class="cx" style="display: block; padding: 0 10px">                                        'Safety Wrangler E-mail Address'                 => 'text',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                        'Mentor WordPress.org User Name'                 => 'text',
</ins><span class="cx" style="display: block; padding: 0 10px">                                         'Mentor Name'                                    => 'text',
</span><span class="cx" style="display: block; padding: 0 10px">                                        'Mentor E-mail Address'                          => 'text',
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -483,27 +491,39 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Adds jQuery UI
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        function admin_scripts() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( get_post_type() == WCPT_POST_TYPE_ID )
-                       wp_enqueue_script( 'jquery-ui-datepicker' );
-       }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         wp_register_script(
+                       'wcpt-admin',
+                       WCPT_URL . 'javascript/wcpt-wordcamp/admin.js',
+                       array( 'jquery', 'jquery-ui-datepicker' ),
+                       WCPT_VERSION,
+                       true
+               );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        /**
-        * Print our scripts for the Edit WordCamp screen
-        *
-        * If this file grows larger, it'd make sense to switch to using wp_enqueue_script().
-        */
-       function admin_print_scripts() {
-               if ( WCPT_POST_TYPE_ID !== get_post_type() ) {
-                       return;
-               }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Edit WordCamp screen
+               if ( WCPT_POST_TYPE_ID === get_post_type() ) {
+                       wp_enqueue_script( 'wcpt-admin' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Default data
+            $data = array(
+                   'Mentors' => array(
+                    'l10n' => array(
+                        'selectLabel' => esc_html__( 'Available mentors', 'wordcamporg' ),
+                        'confirm'     => esc_html__( 'Update Mentor field contents?', 'wordcamporg' ),
+                    ),
+                   )
+            );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                <script>
-                       <?php require_once( dirname( __DIR__ ) . '/javascript/wcpt-wordcamp/admin.js' ); ?>
-               </script>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            // Only include mentor data if the Mentor username field is editable
+            if ( current_user_can( 'manage_network' ) ) {
+                $data['Mentors']['data'] = Mentors_Dashboard\get_all_mentor_data();
+            }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                <?php
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 wp_localize_script(
+                               'wcpt-admin',
+                               'wordCampPostType',
+                               $data
+                       );
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        function admin_styles() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -904,6 +924,27 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Check if a field should be readonly, based on the current user's caps.
+        *
+        * @param string $field_name The field to check.
+        *
+        * @return bool
+        */
+       public static function is_protected_field( $field_name ) {
+               $protected_fields = array();
+
+               if ( ! current_user_can( 'manage_network' ) ) {
+                       $protected_fields += array(
+                               'Mentor WordPress.org User Name',
+                               'Mentor Name',
+                               'Mentor E-mail Address',
+                       );
+               }
+
+               return in_array( $field_name, $protected_fields );
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Add our custom admin notice keys to the redirect URL.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * Any member can add a key to $this->active_admin_notices to signify that the corresponding message should
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1082,6 +1123,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        foreach ( $meta_keys as $key => $value ) :
</span><span class="cx" style="display: block; padding: 0 10px">                $object_name = wcpt_key_to_str( $key, 'wcpt_' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $readonly = ( WordCamp_Admin::is_protected_field( $key ) ) ? ' readonly="readonly"' : '';
</ins><span class="cx" style="display: block; padding: 0 10px">         ?>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                <div class="inside">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1089,7 +1131,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                <p>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <strong><?php echo $key; ?></strong>:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        <input type="checkbox" name="<?php echo $object_name; ?>" id="<?php echo $object_name; ?>" <?php checked( get_post_meta( $post_id, $key, true ) ); ?> />
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 <input type="checkbox" name="<?php echo $object_name; ?>" id="<?php echo $object_name; ?>" <?php checked( get_post_meta( $post_id, $key, true ) ); ?><?php echo $readonly; ?> />
</ins><span class="cx" style="display: block; padding: 0 10px">                                 </p>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        <?php else : ?>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1107,7 +1149,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php switch ( $value ) :
</span><span class="cx" style="display: block; padding: 0 10px">                                                case 'text' : ?>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        <input type="text" size="36" name="<?php echo $object_name; ?>" id="<?php echo $object_name; ?>" value="<?php echo esc_attr( get_post_meta( $post_id, $key, true ) ); ?>" />
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 <input type="text" size="36" name="<?php echo $object_name; ?>" id="<?php echo $object_name; ?>" value="<?php echo esc_attr( get_post_meta( $post_id, $key, true ) ); ?>"<?php echo $readonly; ?> />
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                                <?php break;
</span><span class="cx" style="display: block; padding: 0 10px">                                                case 'date' :
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1119,12 +1161,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                                        ?>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        <input type="text" size="36" class="date-field" name="<?php echo $object_name; ?>" id="<?php echo $object_name; ?>" value="<?php echo $date; ?>" />
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 <input type="text" size="36" class="date-field" name="<?php echo $object_name; ?>" id="<?php echo $object_name; ?>" value="<?php echo $date; ?>"<?php echo $readonly; ?> />
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                                <?php break;
</span><span class="cx" style="display: block; padding: 0 10px">                                                case 'textarea' : ?>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        <textarea rows="4" cols="23" name="<?php echo $object_name; ?>" id="<?php echo $object_name; ?>"><?php echo esc_attr( get_post_meta( $post_id, $key, true ) ); ?></textarea>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 <textarea rows="4" cols="23" name="<?php echo $object_name; ?>" id="<?php echo $object_name; ?>"<?php echo $readonly; ?>><?php echo esc_attr( get_post_meta( $post_id, $key, true ) ); ?></textarea>
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                                <?php break;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre>
</div>
</div>

</body>
</html>