The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Yote Admin Page (YAP)</title>

    <script src="/yote/js"></script>

    <link href="/yote.css" rel="stylesheet" type="text/css" media="all" />
    <link href="/css/main.css" rel="stylesheet" type="text/css" media="all" />

    <META NAME="Author" CONTENT="Eric Wolf, coyocanid@gmail.com">

    <STYLE>
      .mainpanel { top:0px; width:900px; display:inline-block; }
      .tabs {
	  position: relative;
	  min-height: 300px; /* This part sucks */
	  clear: both;
	  margin: 25px 0;
      }
      .tab {
	  float: left;
      }
      .tab label {
	  background: #eee;
	  padding: 10px;
	  border: 1px solid #ccc;
	  margin-left: -1px;
	  position: relative;
	  left: 1px;
      }
      .tab [type=radio] {
	  display: none;
      }
      .content {
	  position: absolute;
	  top: 28px;
	  left: 0;
	  background: white;
	  right: 0;
	  bottom: 0;
	  padding: 20px;
	  border: 1px solid #ccc;
      }
      [type=radio]:checked ~ label {
	  background: white;
	  border-bottom: 1px solid white;
	  z-index: 2;
      }
      [type=radio]:checked ~ label ~ .content {
	  z-index: 1;
      }
      .apppanel { margin-left: 150px; }
     border:none;
     padding:0!important;
    /*border is optional*/
     border-bottom:1px solid #444; ; }
      ._ct_row { vertical-align: top }
      ._ct_cell { border: 6px rgb(120,226,165) groove }


      tr { vertical-align: top }
    </STYLE>

<!--
there is a beauty that we experience as kids that only leaves tiny hints of itself when we are older.
it hides in smells and in the whispered wind.
if we are our experiences then we are both sides of them.

-->

    <script>
      var root;
	  function msg( ctx, message ) {
	      $( ctx.controls.messages ).empty().append( message );
	  }

      $().ready(function(){
          $.yote.debug = false;
	      $.yote.templates.import_templates( '/templates/default_templates.html' );
	      $.yote.init(  );
	      $.yote.templates.init();
	      $.yote.templates.refresh();
      });
    </script>



<script type="text/template" class="yote_template_definition" template_name="Entry_Repeat">
  <table border=1><tr>  <th>Interval (mins)</th>     <th>Infinite Repeat</th>   <th>Repeats</th>
                        <th>Delete</th>
                  </tr>
      <@ Cron_Repeat_Row _@repeats 2 @>
  </table>
  <$$ Paginator _@repeats $$>
  <$$$ newrep <button type="button">add repeat</button> $$$>
    <? function( ctx ) {
        $( ctx.controls.newrep ).click( function() {
            ctx.vars._.add_to( { name : 'repeats', items : [ $.yote.fetch_root().new_root_obj()] } );
	        $.yote.templates.refresh();
        } );
    } ?>
</script>

<script type="text/template" class="yote_template_definition" template_name="Entry_Repeat_Table">
  <!-- pagination goes here. Under the hood, there must be a context container or a default tag, or even last list -->
</script>

<script type="text/template" class="yote_template_definition" template_name="Cron_Repeat_Row">
  <tr>  <td><$$ edit _ repeat_interval $$></td>  <td><$$ checkbox _ repeat_infinite $$></td>  <td><$$ edit _ repeat_times $$></td>  <td><$$$ delme <a href="#">delete</a>$$$></td> </tr>
    <?
    function( ctx ) {
        $( ctx.controls.delme ).click( function() {
            ctx.vars.__.remove_item( ctx.vars._ );
	        $.yote.templates.refresh();            
        } );
    }
    ?>
</script>


<script type="text/template" class="yote_template_definition" template_name="Cron_Schedule_Row">
  <tr>  <td><$ show $></td> <td><$$$ controls remsched <button type="button">remove</button>$$$></td> </tr>
    <? function( ctx ) {
        $( ctx.controls.remsched ).click( function() {
            ctx.vars.__.remove_item( ctx.vars.hashkey_or_index );
        } );
    } ?>
</script>



  <script type="text/template" class="yote_template_definition" template_name="Attached_Objects">
    <table> <TR> <TH>Object Name</TH> <TH>Class</TH> <TH>Remove</TH> </TR>
      <% Attached_Obj_Row _%attached_objects 10 %>
    </table>
    <$$ Paginator _%attached_objects $$>
    <$$ Add_Attached $$>
  </script>

  <script type="text/template" class="yote_template_definition" template_name="Add_Attached">
    <$$$ field <input type="text" placeholder="field"> $$$>
      <$$$ objtype <select> <option value="1">All May Edit</option> <option value="2">User and Root May Edit</option> <option value="3">Root May Edit</option></select> $$$>
	<$$$ add_attached_b <BUTTON type="BUTTON">Attach Object</BUTTON> $$$>
    <? function( ctx ) { 
    $.yote.util.button_actions( 
	{
	    button : ctx.controls.add_attached_b,
	    texts  : [ ctx.controls.field ],
	    action : function() {
		var k  = $( ctx.controls.field ).val();
		var ot = $( ctx.controls.objtype ).val();
		var o = ot == 1 ? $.yote.fetch_root().new_obj() :
		    ot == 2 ? $.yote.fetch_root().new_user_obj() :
		    ot == 3 ? $.yote.fetch_root().new_root_obj() : null;
		if( o ) {
		    ctx.vars._.set( k, o );
		    ctx.vars._.hash( {  name  : '_attached_objects',
                                        key   : k,
					value : o } );
		    $.yote.templates.refresh();
		}
	    } //action
	} );
    }
    ?>
  </script>

  <script type="text/template" class="yote_template_definition" template_name="Attached_Obj_Row">
    <$$$ set fieldname <$ hash_key $> $$$>
      <TR>
	<TD><$ hash_key $></TD>
	<TD><?? function( ctx ) { return ctx.vars._.class } ??></TD>
	<TD><$$$ remove_attached <button type="button">Remove</button> $$$></TD>
      </TR>
    <? function( ctx ) {
	    var dh = ctx.vars.fieldname;
	    ctx.vars.__.set( dh, null );
	    ctx.vars._.delete_key( { name : '_attached_objects', key : dh } );
	    $.yote.templates.refresh();
    } ?>
  </script>

  <script type="text/template" class="yote_template_definition" template_name="Attached_ObjTab">
    <table> <TR> <TH>Object Name</TH> <TH>Class</TH> <TH>Remove</TH> </TR>
      <% Attached_Obj_Row 10 %>
    </table>    
  </script>

  <script type="text/template" class="yote_template_definition" template_name="Email_Settings">
    <table>
      <tr> <td><nobr>Email Validation Required</nobr> </td> <td> <$$ checkbox _ requires_validation $$> </td> </tr>
      <tr> <td><nobr>Validation Email From</nobr> </td> <td> <$$ edit _ validation_email_from $$> </td> </tr>
      <tr> <td><nobr>Validation Subject Template</nobr> </td> <td> <$$ edit _.validation_subject_template text $$> </td> </tr>
      <tr> <td><nobr>Validation Message Template</nobr> </td> <td> <$$ edit _.validation_message_template text $$> </td> </tr>
      <tr> <td><nobr>Validation Link Template</nobr> </td> <td> <$$ edit _.validation_link_template text $$> </td> </tr>
    </table>
  </script>

  <!-- ------------------------------ -->

  <script type="text/template" class="yote_template_definition" template_name="Users">
    <a NAME="Users">
      <h3>Users</h3>
      <table border=1><tr>  
          <th>Handle</th>
          <th>Email</th>
          <th>Is Root</th>
          <th>Was Validated</th>
          <th>Reset Password</th>
        </tr>
        <% User_Row _app_%_handles 1 %>
      </table>
      <$$ Paginator _app_%_handles $$> <br>
       <#$$ SearchHash $$#>
       <br>
       user logins removed : <$$$ rl <span></span> $$$><br>
       <$$$ purge_users <button type="button">Flush all removed users</button> $$$>
       <? function( ctx ) {
           var pu = 1*ctx._app_.count( '_removed_logins' );
           $( ctx.controls.rl ).text( pu );
           if( pu == 0 ) {
               $( ctx.controls.purge_users ).prop( 'disabled', true );
           }
           $( ctx.controls.purge_users ).click( function() {
               if( confirm( 'Really purge ' + pu + ' removed users?' ) ) {
                   ctx._app_.purge_deleted_logins( '',
                                                   function(retmsg){ 
                                                       msg( ctx, retmsg ) },
                                                   function(err){ 
                                                       msg( ctx, err ) } );
                   $.yote.templates.refresh();
               }
           } );
       } ?>
   </script>

   <script type="text/template" class="yote_template_definition" template_name="User_Row">
     <tr>   
       <th><$ _hashkey_ $></th>
       <th><$ _.email $></th>
       <th><??? function( ctx ) { 
          var login = ctx.vars._;
          return login ? login.is_master_root() ? 'master root' : 
                            '<$$$ toggle <input type="checkbox"> $$$>' : ''; 
          } ???></th>
       <th><??? function( ctx ) {
               return ctx.vars._ && ctx.vars._.is_validated() ? 'Yes' : 'No <$$$ makevalid <button type="button">validate</button>$$$>' } ???>
       </th> 
       <th> <$$$ newp <input type="password" placeholder="new password">$$$> <$$$ newpup <button type="button">Update</button>$$$></th>
     </tr>
     <? function( ctx ) {
         if( ctx.vars._.get_is_root()*1 == 1 ) {
             $( ctx.controls.toggle ).attr( 'checked', true );
         }
         $( ctx.controls.toggle ).change( function() {
             if( $(this).is( ':checked' ) ) {
                 ctx._app_.make_root( ctx.vars._, function(){}, function(err){ alert(err) } );
             } else {
                 ctx._app_.remove_root( ctx.vars._, function(){},function(err){ alert(err)} )
             }
             $.yote.templates.refresh();
         } );
         $( ctx.controls.makevalid ).click( function() {
             ctx._app_.root_validate( { l : ctx.vars._ },
                                 function( pass ) { 
                                     msg( ctx, pass );$.yote.templates.refresh();
                                 }, function( err ) { msg( ctx, err ); } );
         } );
         $( ctx.controls.newpup ).click( function() {
             ctx._app_.root_reset_password( { p : $( ctx.controls.newp ).val(), l : ctx.vars._ },
                                     function( pass ) { 
                                         msg( ctx, pass ); $.yote.templates.refresh();
                                     }, function( err ) { msg( ctx, err ); } );
         } );
     } ?>
   </script>

   <!------------------------------------------->
   <!----                 CRON               --->
   <!------------------------------------------->

   <script type="text/template" class="yote_template_definition" template_name="Entry_Schedule_Table">

       <!-- pagination goes here. Under the hood, there must be a context container or a default tag, or even last list -->
   </script>

   <script type="text/template" class="yote_template_definition" template_name="Entry_Schedule">
     <table border=1><tr>  <th>Scheduled Time</th> <th>Delete</th> </tr>
       <@ Cron_Schedule_Row _@scheduled_times 2 @>
     </table>
     <$$ Paginator _@scheduled_times $$>
     <$$$ new_schedule_time <input type="datetime-local"> $$$>
     <$$$ new_schedule <button type="button">Schedule Time</button> $$$>
     <? function( ctx ) {
         $( ctx.controls.new_schedule_time ).click( function() {
             alert( $( ctx.controls.new_schedule_time ).val() );
            
         } );
     } ?>
   </script>

   <script type="text/template" class="yote_template_definition" template_name="Cron_Row">
     <tr> <td> <$$ edit _ name $$> </td>  <td> <$$ checkbox _ enabled $$> </td>  
       <td> <$$ edit _ notes $$> </td> <td> <$$ edit _ script $$> </td>  
       <td> <?? function( ctx ) {
           var entry = ctx.vars._;
           if( ! entry ) return '';
           return entry.get( 'next_time' ) > 0 ? '<nobr>' +  $.yote.util.format_date( new Date( 60 * 1000 * entry.get( 'next_time' ) ), "h:m Y-M-D" ) + '</nobr>' : 'Not Scheduled';
           } ??> </td>  <td> <$$ Entry_Repeat $$> </td>
       <td> <$$ Entry_Schedule $$> </td>  <td> <$$$ del <button type="button">delete</button> $$$> </td>
     </tr>
    <? function( ctx ) {
        ctx.vars.cron.update_entry( ctx.vars._ );
        $( ctx.controls.del ).click( function() {
            ctx.vars.cron.remove_from( { name : 'entries', items : [ ctx.vars._ ] } );
            $.yote.templates.refresh();
        } );
    } ?>    
   </script>

   <script type="text/template" class="yote_template_definition" template_name="Cron_Table">

   </script>

   <script type="text/template" class="yote_template_definition" template_name="Cron">
     <??? function( ctx ) {
         ctx.vars.cron = ctx._app_.cron();
     } ???>
     <A NAME="Cron">
       <H3>Crons</H3>
       <table border=1><tr>  <th>Name</th>     <th>Enabled</th>   <th>Notes</th>
           <th>Script</th>   <th>Next Run</th>  <th>Repeat</th>
           <th>Schedule</th> <th>Delete</th>
         </tr>
         <@ Cron_Row cron@entries 5 @>
       </table>
       <$$ Paginator cron@entries $$> <br>

       <$$$ newbutton <button type="button">Add Cron</button>$$$>
       <?
           function( ctx ) {
               $( ctx.controls.newbutton ).click( function() {
                   var newc = ctx.vars.cron.new_with_same_permissions();
                   ctx.vars.cron.add_entry( newc );
                   $.yote.templates.refresh();
               } );
           }
        ?>
   </script>


   <!------------------------------------------->
   <!----                 APPS               --->
   <!------------------------------------------->

   <script type="text/template" class="yote_template_definition" template_name="NewApp">
     <div class="newapp">
       <h3>Create a new App</h3>
       App Name <$$$ name <input type="text"> $$$><BR>
       App Class <$$$ appclass <input type="text" value="Yote::AppRoot"> $$$><BR>
       <$$$ new_app_b <button type="BUTTON">Register App</BUTTON> $$$>
     </div>
     <? function( ctx ) {
     $.yote.util.button_actions( {
         button :   ctx.controls.new_app_b,
         texts  : [ ctx.controls.name ],
         action : function() {
         var newapp = ctx.vars.root.register_app(
             { 'name'    : $( ctx.controls.name ).val(),
               'class' : $( ctx.controls.appclass ).val() 
             },
             function() { $.yote.templates.refresh() },
             function(err) { msg( ctx, err ); }
         );
         } 
     } );
    } ?>
   </script>

   <script type="text/template" class="yote_template_definition" template_name="App_Row">
     <tr>   <td><$ _hashkey_ $></td>     <td><$$ edit _ host_name $$></td>   <td><$$ edit _ host_u2rl $$></td>
       <td><?? function(ctx) { return ctx.vars._.count('_account_roots'); } ??> </td>   
       <td><$$ Email_Settings $$></td>  <td><$$ Attached_Objects $$></td>
       <td><$$$ reset_b <button type="button">Reset</button>$$$></td>
     </tr>
     <?
        function( ctx ) {
        $( ctx.controls.reset_b ).click( function() {
            if( confirm( 'really purge app ' + ctx.hashkey ) ) {
            ctx.vars.root.purge_app( ctx.vars._ );
            $.yote.templates.refresh();
            }
        } )
        }
     ?>
   </script>


   <script type="text/template" class="yote_template_definition" template_name="Apps">
    <A NAME="App">
    <H3>Applications Installed</H3>
    <???
    function( ctx ) { 
        $.yote.debug = true;
        var root = $.yote.fetch_root();
        ctx.vars.root = root;
        var app_count = root.count( '_apps' );
        var pag = root.wrap_hash( { collection_name : '_apps', cache_key : 'foo', wrap_key : 'bar' }, app_count );
        var app_hash = pag.to_hash();
        var apps = {};
        for( var k in app_hash ) {
            if( app_hash[ k ] ) 
                apps[ k ] = app_hash[ k ];
        }
        console.log( [ 'APPS', apps, pag, app_hash, app_count, root ] );
        ctx.vars.apps = apps;
        $.yote.debug = false;
    } ???>
    <table border=1><tr>  <th>Name</th>     <th>Host</th>   <th>Host URL</th>
        <th>Number of Users</th>   <th>Email Settings</th> 
        <th>Attached Objects</th>  <th>Reset</th>
      </tr>
      <% App_Row %apps 3 %>
    </table>
    <$$ Paginator %apps $$> <br>
    <#$$ SearchHash $$#>
    <??? function( ctx ) {
        var pc = $.yote.fetch_root().count( '_purged_apps' );
        if( pc > 0 ) {
            return pc + ' apps thate have been purged <$$$ purge_apps <button type="button">Flush all Purged Apps</button> $$$>';
	    } 
	    return '';
    } ???>
    <$$ NewApp $$> <br>
    <$$$ flush_obj_cache <button type="button">Flush Object Cache</button>$$$> <BR>
    <$$$ flush_old_login <button type="button">Flush Old Login Tokens</button>$$$>

    <? function(ctx) {
	    $( ctx.controls.purge_apps ).click(function(){
	        ctx.vars.root.flush_purged_apps(
                undefined,
		        function(){ $( ctx.controls.messages ).empty().append( 'flushed purged apps' ) },
		        function(err){ $( ctx.controls.messages ).empty().append( err ) }
	        ); 
        } );
	    $( ctx.controls.flush_obj_cache ).click(function(){
	        ctx.vars.root.reset_connections(
                undefined,
		        function(){ $( ctx.controls.messages ).empty().append( 'flushed object cache' ) },
		        function(err){ $( ctx.controls.messages ).empty().append( err ) }
	        ); 
        } );
	    $( ctx.controls.flush_old_login ).click(function(){
	        ctx.vars.root.clear_old_tokens(
                undefined,
		        function(){ $( ctx.controls.messages ).empty().append( 'flushed old tokens' ) },
		        function(err){ $( ctx.controls.messages ).empty().append( err ) }
	        ); 
        } );
    } ?>
    </script>


  <!------------------------------------------->
  <!----                 MAIN               --->
  <!------------------------------------------->

  <script type="text/template" class="yote_template_definition" template_name="Empty">
     None Found
  </script>

  <script type="text/template" class="yote_template_definition" template_name="MainAdmin">
  </script>


  <script type="text/template" class="yote_template_definition" template_name="AdminBody">
    <DIV class="mainpanel">
      <SECTION>
	<DIV class="page-header">
	  <H1>Yote Admin Page (YAP)</H1>
	</DIV>
	<P>
	  Welcome to the Yote Admin Page. This page manages
          the <A HREF="#Users">users</A>, <A HREF="#App">apps</A> and <A HREF="#Cron">cron</A>.
	</P>
      </SECTION>
      <hr>
       <$$$ messages <span class="message"></span> $$$>
       <$$ Apps $$>
       <hr>
       <$$ Cron $$>
       <hr>
       <$$ Users $$>
     <BR>
      <A HREF="#Top">Back to Top</A>
     </DIV>
  </script>

  <script type="text/template" class="yote_template_definition" template_name="MainBody">
    <??? function( ctx ) {
         return $.yote.has_root_permissions() ?
	    '<$$ AdminBody $$>' :
	    '<DIV id="errpanel" class="err">Must be logged in with a root account to view this page. ' + ( $.yote.is_logged_in() ? '<$$$ lo <a href="#">$$$>logout</a>' : '' ) + '</DIV>';
        } 
    ???>
    <? function( ctx ) { $( ctx.controls.lo ).click( function() { $.yote.logout() } ); } ?>
  </script>

  </head>

  <BODY>
    <DIV class="yote_template" template="YoteHeaderAdmin"></div>
    <A NAME="Top"/>
    <DIV class="yote_template main" template="MainBody"></div>
  </body>
</html>