Laravel and CAS, the finale to my auth journey

Quick Background

I’m sure most users won’t need to setup CAS, but I work for a college and we use CAS everywhere.  This means, that our custom applications have to as well.

I started this journey yesterday, and was able to get CAS setup and working pretty quickly, however it was only after some struggle I was able to crack the code on how to access it from a Blade template.  This may be pretty easy for a veteran to recognize how to do, but a veteran I am not, as you can see from my tweets and previous posts.  

In typical fashion, I’m blogging what I did, mostly as reference for me, for next time, but also in the hope that it will help some other newb… non-veteran.

I did what I normally do when looking for something like this, start with google, and usually end up on Packagist, or something.  I found an older CAS package, that said it worked with 5.x, but I was a bit worried it may not like 5.5, so I kept looking and found one by Subfission It specifically mentions 5.5, it has a wiki, and seemingly good instructions.  I created a feature branch for my app (I use GitFlow) and set it up.

The Install

First – you don’t need to do this, other than to get some extra blade template code from it) but I installed the normal Laravel Auth stuff (here’s a link to the docs if you need help with that).  This created a nice header in the blade template that I hacked up for my app.  Again, you don’t have to do this, it was just part of my auth-journey and migration.

The installation instructions are close to perfect, although it does mention adding the ServiceProvider and Facade lines to app.php, which isn’t necessary for Laravel v5.5+ – you can skip those little sections.  You do have to add a couple lines to /App/Http/Kernal.php, a simple copy/paste job and that’s done. 

protected$routeMiddleware=[
  'auth'=>\Illuminate\Auth\Middleware\Authenticate::class,
  'auth.basic'=>\Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
  'bindings'=>\Illuminate\Routing\Middleware\SubstituteBindings::class,
  'can'=>\Illuminate\Auth\Middleware\Authorize::class,
  'guest'=>\App\Http\Middleware\RedirectIfAuthenticated::class,
  'throttle'=>\Illuminate\Routing\Middleware\ThrottleRequests::class,
  'cas.auth'=>'Subfission\Cas\Middleware\CASAuth',
  'cas.guest'=>'Subfission\Cas\Middleware\RedirectCASAuthenticated',
];

I left the old auth settings in there, but these could be removed if you want them to.  Actually the probably should be because otherwise you can still back-door the old auth login, registration, etc.

After editing Kernel.php, pop back to the terminal and run 

php artisan vendor:publish

Doing this,  creates the config/cas.php file that you’ll have to edit and add your network’s CAS settings to.  We have a CAS server here, and I’ve setup many phpCAS applications using classic PHP, so these were a no-brainer for me.  Check with your network team, or whomever manages your CAS server for these if you don’t have them. For ours here, I only had to edit the lines that referenced the host name, there were 3 : cas_hostname, cas_real_hosts, cas_logout_url, I left the other settings as default, and they work perfectly.

You’re (hopefully) golden. Now what do you do?

First, you’ll need to require CAS authentication in your controller method.  There may be better ways to do this, and if I find one, I’ll update this post – and probably tweet it out, but I added this __construct to the top of my MainController

public function__construct()
{
    $this->middleware('cas.auth');
}

This tells the controller all methods in it requires our CAS authentication. 

I created an index method in MainController like the one below. I was testing and I sent the blade variable “user”. That can be accessed via cas()->user() in the controller and that will be the username of the authenticated user. 

Like this:

public function index (Request $request)
{
   $user = cas()->user();
   ...
}

(For the record, you can use all of these methods in your controller if you need to.)

This is useful if you need to know the user for other function calls in the method.  For our test however, we’ll just send it through to our blade view like this.

public function index (Request $request)
{
  return view('index',[
    'user'=>cas()->user()
  ]);
}

I guess we’ll need a quick blade template to display something to prove this works.  Create an index.blade.php file and toss this in for a quick-n-dirty test:

Hello {{ $user }} !

Next, set up a route to test this out and cross your fingers.

Route::get('/', 'MainController@index')->name('home');

If you have it setup correctly, when you hit this path, it’ll pop to your CAS login.  This is nice, because as a developer, I don’t have to design a login page now 🙂 

One note here, I had to email our network team to have my local domain added to the CAS server configuration because I was getting a “this application is not authorized to use this service”.  Once they added my Homestead’s domain name – portal.test I was all set.

Once you log in, it’ll pop back to your view with you logged in and it should display

Hello jwheat ! (...or whomever you logged in as)

Congrats! You’re done! It Works!

Taking it a bit further

Here’s where I used the default auth blade code.

When initially setting up Laravel’s auth, it creates some blade templates with various logged-in checks.  Take a look here to see what the default “if” statement looks like.  I’ve bolded the bits below that we care about right now

 

 

Looking through that, you can see the template check to see if the user is a guest, to display the login and register links, if they’re not a guest, meaning they’re logged in, it will display their name.

With our new CAS setup, this can be changed to achieve the same results.  I have to admit it took me a bit to figure out, but once I did, it made complete sense.  There are no google results that will tell you how to check this in a blade template, so this could be THE. ONLY. PLACE. on the internet telling you 🙂  Ok, this is where the non-veteran thing comes in because its possible this is child’s play, but here it is anyway

@if ( !Cas::isAuthenticated() )

<li class="nav-item"><a href="{{ route('login') }}" class="nav-link">Login</a></li>
<li class="nav-item"><a href="{{ route('register') }}" class="nav-link">Register</a></li>
@else
<li class="nav-item dropdown">
    <a href="#" class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown"
       aria-haspopup="true" aria-expanded="false">
        {{ Cas::user() }}
    </a>
    <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">
        <a href="{{ route('logout') }}" class="dropdown-item"
           onclick="event.preventDefault();document.getElementById('logout-form').submit();">
            Logout
        </a>

        <form id="logout-form" action="{{ route('logout') }}" method="POST"
              style="display: none;">
            {{ csrf_field() }}
        </form>
    </div>
</li>
@endif

With this CAS package, there isn’t a guest option, you’re either authenticated or not by checking – Cas::isAuthenticated() .  So I’ve kept the logic the same with the “guest” check at the top, and just tossed in a ! (not) in front.

I also need to change the routes listed in the code since the ones listed are part of the normal Auth package.  In this implementation having a register link is silly because user creation is handled by a much larger external process/system.  The login link doesn’t make sense because the entire view itself forces you to login immediately.  I guess if this were a public page with a link to login, you’d simply route to the first view in your secured app and you’d get the login page.  The Logout link can simply change to Cas::logout() Done.

What is cool here (remember me? non-veteran) is that all the methods listed on this page are all accessible in blade using Cas:: in front instead of cas()->.  That was the secret sauce I needed, the nut to crack if you will.  There is even one for Dynamic calls allowing you to call other phpCAS functions not built into this package.

Some caveats with CAS

CAS only gives you a username coming back from an external system.  If you need a local user profile on your system and collect other information like an Avitar or preferences, you’ll have to handle that yourself.  This app I’m building requires much more information, roles, etc so this is clearly just a jumping off point for me.  I’m expecting my next post will be how to create a new user locally after that first CAS login.

So there ya go, you can implement CAS into your Laravel applications now and if you work for an institution that uses CAS, you’ll be a hero.

Until my next #LessonLearned, enjoy.

Posted in Laravel, LessonsLearned | 2 Comments

The Laravel Service Container, not as scary as you think

Yea, it sounds scary when someone mentions the IoC or Service Container, but it is a really easy and elegant way to store classes, and other data to retrieve later throughout your app.

I have a one-database multi-tenant app – which is a fancy way for saying multiple clients (tenants) who use the same codebase and can access only their data.  Each client has its own url, a CNAME that is setup, so I can look at that to determine what client I need to display content for and tailor the UI for them.

There are different ways to do this, and here are a few options depending on what you want to achieve. The first is the “typical” way I guess you could call it.

Option 1: No Container, make the call in all your controllers

In any / all of your controllers you could simply get the current client with something like this.

$client = \App\Client::getClientInfo();

In the Client model you’d have this method

public static function getClientInfo()
{
    return \App\Client::where('client_url', '=', $_SERVER['SERVER_NAME'] )->first();
}

This looks at the url, and hits the database and returns the client record that corresponds to that url.  Simple.  So why not do it this way?  First, this does not use the container, therefore your “current client” data it scoped locally within this method in the controller and you’re doing the lookup each time this executes.  While it totally works, and is easy to setup, its not ideal for those reasons.  We always have to do that lookup each time we want to know who’s using our app. (Yes you could store it all in a session if you wanted, but we don’t)

Option 2: Store the entire class for later

An alternate method that is similar functionally to the one above but uses the Service Container works this way.

In the boot method of AppServiceProvider.php you would bind the Client class in the container like this –

$this->app->bind('Client', \App\Client::class);

Then in say the DashBoardController.php (and really all controllers you need this information in) you can pull it out and call a method in it like this –

public function index()
{
   $client = app()->make('Client')->getClientInfo();
}

Now the $client variable references the Client class we bound in the service container and by chaining the getClientInfo method call you can pull out the current client’s record. Just like option 1 above,  the getClientInfo method contains the logic to look at the url to decide which client it is (note this time it’s not a static method)

public function getClientInfo()
{
    return \App\Client::where('client_url', '=', $_SERVER['SERVER_NAME'] )->first();
}

This is a baby step toward using the container, you’re storing the class, but you’re still doing a lookup every time you want the information.

But, there’s a better way!

Option 3: Store the current client in the Service Container instead

This is the method I chose, so whenever I pull it out, my $client is already determined and everything is at my fingertips.

Just like option 2 above, I setup my binding in the boot method of AppServiceProvider.php, but this time we’ll handle the URL logic here instead

app()->bind('Client', function() {
    return \App\Client::where('client_url', '=', $_SERVER['SERVER_NAME'] )->first();
});

At first glance that looks overwhelming, I thought that too.  Here’s the rundown of what its doing, its pretty simple once you understand it… I guess most things are 🙂

We’re going to setup a new binding (think of it as a bucket for now) and I’m naming it ‘Client’ (the green text).  Don’t get confused, I could have called it CurrentClient or anything that makes sense to me.  I just stuck with Client because that’s what I called the model. The callback function (everything in the curly brackets / purple text) is what we’re going to execute and place its results into our Client bucket.  You’ll recognize the following code from Option 1 and 2’s getClientInfo method – its the same simple code

return \App\Client::where('client_url', '=', $_SERVER['SERVER_NAME'] )->first();

it calls our Client model (not the biding bucket) and selects the client record from the database that matches our url.  With the return tacked to the front of this line inside our bind statement, it will return that client record INTO our Client bucket. To explain in simple terms, we shoved our current client into our bucket for later.

What we have then is a new Service Container binding called Client that holds our current client based on the url of the app.

Great, so now what?

We use it!

In our controllers, yes we still have to pull it out in each one, but there’s no database lookup each time – we do this

$client = app()->make('Client');

and now I have the current client object available to me and I can use something like $client->id to go pull content, settings or pull out the name, logos, and colors from that object to alter the UI specifically for them.

Where to go from here

You can use these bindings for anything you want, classes like we’ve seen above, configuration settings, strings, variables, constants. The container is really nice once you get the hang of it.

 

 

Posted in Laravel | Leave a comment

Learning Laravel: (re)Building against a legacy database

My ConferenSpy rewrite project I mentioned in this post is using the MySQL database that existed for the original – still running and being used by clients – system.  Like the title above implies, I’m learning Laravel and I want to comply with its standards and defaults as much as I can.  I ran straight into an issue with that ideal when I created my first model.  My table names are all lowercase, aren’t plural, and have underscores in them.

Being new, I found that I could place

// Set up legacy table structures
protected $table = 'conference';
protected $primaryKey = 'conference_id';

in the model to make Laravel conform to my database.

I’m moving  along with the rewrite and every model I’ve created I’ve had to change the table name and sometimes the primary key to make them work.  As I was working outside this evening I had an idea to how to move closer to the Laravel way.  The idea was, rename the actual database table to conform to Laravel naming standards, then create a view with the original table name as the view name.  It was crazy enough to work, a least for selects.  A quick google search started to let air out of my idea because to insert using a view, the syntax changes for all of the examples I looked at.

I decided to give it a try anyway, like most things I like to see the failure myself and deal from there.  I renamed the main table “conference” to “Conferences”, created a view called “conference” and grimmaced a bit as I logged into my app.

IT. WORKED.  This is freaking fantastic!

I know some of you are thinking – so what if the table names are a bit wack and don’t match up, the definition is in the model,  you can figure it out.  While that’s true, there’s just something about doing it right that I like.

My next thought is the primary key.  I don’t have it as “id” in most tables because its actually useful with spaghetti PHP to have it in the format of “tablename_id” when doing a lot of joins.  For this table, the primary key is in that format as “conference_id”.

I changed the view to rename the id column conference_id, granted creating a view to do this requires a little more work typing out all the fields, but it’s worth it if it works.

SELECT id as conference_id,
conference_name,
...[snipped]...
conference_active,
client_id,
FROM `Conferences`

I tested this by logging into my app again and creating a new conference, and then editing a conference, and changing conferences to edit, PERFECT! I was stunned actually, its so simple, and no one ever explains how to do this if you wanted to, mostly because if you’re learning you’re creating migrations to build out your database.  Its probably an edge case to keep an older database with a rewrite (typical me, edge case), but whatever, this is GOLD. (can you tell how excited I am?)

My Conferences table now complies with Laravel naming standards so my new code is compliant. The app that clients are using still works which is really more important than anything.  And I know now that I can do this to all of my tables, and from here on out, models will be right.

I’ll call that a good evening of learning and experimentation.

Posted in Laravel | Leave a comment

Learning Laravel: dynamic domain control

EDIT: Fun fact.  Literally about 3 hours after I posted this, I learned this is called Multi-tenancy, which is what I’m describing below and how I achieved it my way as a Laravel newbie.  Now I’m seeing there is a better way and will post again with what I’ve learned.  Feel free to read this anyway, maybe I’m closer to doing it right than I think.

I’ve been toying with Laravel a bit, I purchased Laravel Up & Running after having seen many good reviews about it, and I even subscribed to Laracasts almost a year ago, wanting to learn, but not having a project to use it on.  That opportunity finally came, and I built a small user role management system for work. Its only 3 controllers, 1 model and two views. It was actually fun to use and I learned a lot by actually putting the things I had seen in the videos to practice.  I wanted to tackle something a bit larger.

I’ve written a Conference Management System (CMS – yea I know the ‘C’ usually stands for content) called ConferenSpy in “classic PHP” that allows conference admins to manage all aspects of a conference, workshop or event from venue setup to final evaluations, all with an accompanying mobile app for attendees to use during the conference.  I have two clients who hold large annual conferences (about 700 and 2000 attendees respectively) and smaller workshops and tech days throughout the year.

The event registration system was a small enough piece of this app (yea right) that I figured I’d tackle that with Laravel. The important thing to note is that the entire codebase (every .php page) reacts to the url that is given in this way –

http://{clientname}.conferenspy.com.  My php code then uses the url to get the client ID to pull content, configuration, etc.

If someone visited say http://pepsi.conferenspy.com – that would display the login page for the CMS for the Pepsi client.

The event url that contains the event information and registration links is pretty ugly right now and looks like this –

https://pepsi.conferenspy.com/event/event_details.php?Challenge2017

This allowed me to know the client was Pepsi, and I could grab the query-string to know which conference it is (Challenge2017).  I know some rewrite rules could have cleaned that up but whatever, they usually post a link on their site, or email it out.

Enter Laravel

I needed to achieve this with Laravel and found Route groups to be helpful.  I was able to put together a nice clean group to deal with this.  As I was planning this rewrite, I decided that I wanted the url to be useful for the CMS login as well as allow for an easy registration/event url, one you could remember like http://laracon.us (which I’m going to!)

I wanted something like this:

http://pepsi.conferenspy.com – just like above

http://challenge2017.conferenspy.com – would be the new easy url for the event page and registration links

This is a different approach than I had with my classic PHP app, but its much friendlier and easy to remember than the old event url format.  My route configuration has to get a portion of the url and determine whether it is a client or an event and serve up the appropriate view

Route::group(array('domain' => '{eventname}.{domain}.{ext}'), function()
{
    Route::get('/', function($eventname)
    {
      /**
      * This method determines if there is a conference configured for the URL specified
      * if there is, display the main event page for the event based on the URL
      * and if not it will redirect to the client /hub login if there is a configured
      * client for the URL specified.
      * ie.  http://codestorm.conferenspy.com -> redirect to /hub
      *      http://storm2017.conferenspy.com -> load event page for this event
      *      http://foobarnow.conferenspy.com -> load a "404" page
      **/

      $event_tag = str_replace(" ", "", $eventname);
      $is_event = App\Conference::where('conference_url', strtolower($event_tag))->first();

      if ($is_event == NULL) {
         // check for client configuration
         $is_client = App\Client::where('client_name', strtolower($event_tag))->first();

         if ($is_client == NULL) {
            // display url not configured page
            return view('site-not-found');
         } else {
            // display login
            return view('client-login');
         }

       } else {
         // This is an event url, run controller and method
         $app = app();
         $controller = $app->make('App\Http\Controllers\EventController');
         return $controller->callAction('displayEventDetails', $parameters = ['conference_id' => $is_event->conference_id]);
        }
    });

});

First – I know you’re thinking – why the heck are you doing {eventname}.{domain}.{ext} ?  Well because I have a different domain configuration on my local machine so I had to make both domain and ext variable and this worked, I don’t do anything with those however. If there’s an easier way to achieve the url parsing, let me know, I’m all about learning this.

Along those lines, since I’m new to this, I’m hoping that’s the proper way to call the EventController, it seems to work, but its a bit ugly.  If not, please feel free to comment and let me know if there’s a better, cleaner way.

I’ve also noticed as I build this out that I’m repeatedly passing objects around through the registration process.  I’ve read a bit about Composite Views, but not sure if that’s what I want, or how to implement them and not sure if that helps me not having to pass around objects or call methods to get data for the views (see still learning).

People joke about spaghetti PHP code and how a framework like Laravel can solve that. At times the Laravel code I’m writing looks elegant, and at other times, I’m not so sure.  It’s probably the learning curve and this being my first big app, I’m betting I’m creating spaghetti Laravel.  Sounds like a good title for a future blog post.

If you have suggestions or pointers feel free to comment, but remember, even though I have a copy of Laravel Up & Running, I may not (yet) understand what you’re saying 🙂

 

Posted in Laravel | Leave a comment

FTC and Vuforia

If you’re reading this, chances are you’re part of an FTC robotics team and trying to figure out Vuforia.  It looks crazy intimidating, but it really isn’t that difficult to get setup and running.  Once its going, you can play around with programming it to recognize other elements of the game field to aid in autonomous navigation.

Below is a quick tutorial I put together as I worked through the entire process.  Follow this step by step and you’ll be able to get the bot’s camera to recognize elements of the field.

To implement Vuforia, you’ll need to create an account and generate a license key.  This is free to do, and quite easy.

Register and obtain a license key

  • Register for a Vuforia developer account here – https://developer.vuforia.com/user/register
  • After you’ve completed the registration, check your email and click on the link to validate your account
  • Log into the Dev Portal after its validated
  • From there, click the Develop tab which will take you to the license manager screen.  If that doesn’t work for some reason you can just click this link vuforia_develop_tabhttps://developer.vuforia.com/targetmanager/licenseManager/licenseListing
  • Create your Vuforia license key
    • Click – Add License Key
      • Choose Development
      • Name it (use your team name or bot name)
      • Device Type : Mobile
      • License Key : Develop – no charge
      • Click Next
      • check box to confirm the agreement, feel free to read it first if you have time 🙂
      • click Confirm
  • Keep this browser window opened, we’ll need it in about 5 minutes.
Lets Get To Work!
Now that you have your key copied we’ll work in Android Studio and create your new class.
 
Create a new class for your project
    • open Android Studio
    • Navigate to FtcRobotController > java > org.firstinspires.ftc.robotcontroller > external.samplesandroid_studio_project_class
    • find the ConceptVuforiaNavigation class
    • right click on it copy the class
    • Navigate to TeamCode > java > org.firstinspires.ftc.teamcode  (you can see two of our other opcodes listed below, you won’t have those.android_studio_team_code
    • Right click on org.firstinspires.ftc.teamcode
    • Choose Paste to create a new class here
    • A dialog box will pop up asking you to give your new class a name ( I chose SciTechVuforia )
    • If the class didn’t open when it pasted, double click on it to open it.

    Enable the opcode

    • The new SDK allows you to easily include opcodes from the actual class itself, instead of having to register it in a separate file like last year.  To enable your new class, scroll down find and comment out or remove the @Disabled line by either deleting it or adding // in front
      for example comment it out like this :    //@Disabled
    • You can also set the name and group for your new opcode with the following line
      @Autonomous(name=“Concept: Vuforia Navigation”, group =“Concept”)
      We’ll just leave this as is, so on our Driver Station, when we get there shorty, you’ll see “Concept: Vuforia Navigation” listed.
  • Now lets add your Vuforia License Key
    Scroll down  a bit and find the line that reads:
    parameters.vuforiaLicenseKey = “”
  • vuforia_license_keyCopy your license key
    • Flip back to your browser where you have Viewforia opened on the License Manager Screen.  If its not there, log in and click the Develop tab.
      • click the name of the key you created and it will display a screen like the image on the right (I’ve smudged out mine for security reasons)
      • select and copy the entire key
  • Flip back to Android Studio
  • Paste your key between the quotes leave the default concept code as is, this will use the back facing camera (NOT the selfie camera)save your changes
That’s all the code and setup you need to do.
 
Lets Test your set up
  • plug in your robot controller phone to the computer
  • From the Android Sudio menu bar choose Run > Run ‘Team Code’ and compile the app to your phone
  • android_sudio_run
  • When the build is successful, and like normal you see the app open on the phone, disconnect it and hook it up on our bot
  • On the driver station phone :
    • choose autonomous
    • pick Concept: Vuforia Navigation  (or if you named it something different above)
    • tap init
    • a rectangle for the camera image will display, this is a good thing
    • tap start
    • a camera image should display on the robot controller screen, using the back camera (not the “Selfie” one)
    • telemetry data should appear on the driver station phone
  • If this is working, Congratulations, your code is all good, no typos.
 
Test the image recognition
stones_chips_locationThere are images you can use to test this located in the FTC App SDK you’ve downloaded.  Open up Explorer (or Finder on Mac) and find the directory  /ftc_app/docs/media.   In here there will be two images, stones.jpg and chips.jpg.  For now, just choose to open one of them on your computer screen (we’ll save some paper and won’t print these).
 
 
Now the fun part.  Turn your camera so it points to the image on your screen, and if you look on the robot controller phone screen, you’ll see the image with a superimposed blue,red and yellow axis.  The phone recognizes the image and displays the X,Y,Z axis over it.
 
 
Look at the telemetry data on your driver station, and you should see one of the targets is visible, along with telemetry data about the camera position in relation to the image, and “the field”.
 
 
The SDK comes with a target database that contains the real Vortex images, so you don’t need to train the app to recognize those.  There are tutorials on You Tube if you want to train it to detect other images or objects and the Vuforia website helps you do this as well.  Just check out their Target Manager section and the tutorial on Model Targets
 
Good luck!
 

 

 

Posted in FTC | Leave a comment

Part 1 – The Idea : Adding Machine Learning to RT (Request Tracker)

We use RT, or Request Tracker from Best Practical, and it works very well.  The issues we have all stem from the people using it.  To give you some background, our department (Computing Services / ITS) is made up of 4 individual units I guess you could say and they make up our large dysfunctional family.

I’ll be very general from now on, as to not point fingers and call any one particular group or person out.  There are a few issues with the interaction of these groups when working “together” with RT.  These seem pretty petty on one level, and could be solved with a “How we use RT” document (cough *policy*), however they’re as real as this blog post.

When we first started using RT, there was some basic training on its features, how tickets moved through the system as a whole, how to pass off and steal tickets if needed, etc.  We never had a document effectively telling us how to use it institutionally.  There was no RT Strategy or grand vision, it was installed to be a ticket system and possibly knowledge base.  Due to this oversight, each group uses RT differently, and to be honest, some people within each group use it differently depending on what they support

There is a culture that each group works autonomously, meaning groups rarely work together on things.  Granted, if there’s a database issue, and the DBA finds an underlying network problem, sure, those two will work together to get it fixed, but in general there are chasms between us which leads to the next issue.  People in group B don’t appreciate being told by group A (aka phone calls, emails, personal visits) to go look at RT because there is a ticket out there that may (or may not) apply to their expertise. Wait, I know what you’re going to say, they should monitor RT more so they can jump on the ticket and not get nagged.  The problem here is RT monitoring can’t be a full time job, and if you’re working on something, you probably can’t be looking at RT at the same time.  This issue caused such a rift that it changed how group A contacts group B, and the way A process tickets for B. Craziness.

Another issue is that tickets coming into group A were being assigned to people in group B, when A has no idea what B does, and often times mis-assigned tickets.  Again, sounds petty, just removed yourself from the ticket, or reassign it yourself.  The heart of this issue is that typically not enough information was in the ticket and a quick assumption of who does that job was made and the ticket was assigned to the wrong person.  That not only inconveniences the new owner of the ticket, it also delays the resolution because it gets passed around until it lands on the right one.  In this scenario, who’s job is it to request more information?  The assigner, or the assignee? People in general don’t appreciate getting work handed to them by people that aren’t they’re boss, and for the record the boss didn’t like his people being assigned things either.

To sum it up, everyone seems to use it a bit differently, we don’t like to be nagged by another group and especially don’t like getting work added to our plate by just anyone.

Wow, right?  What a mess.  Again, kind of petty, yet a bit serious.

How do you deal with personal, and personnel issues like this?  Create policy, rules and regulations, a SOP manual for RT and have more people pissed because they’re being forced to change how they do their job? (which most everyone does well btw).

Enter Machine Learning.

I was out splitting wood a couple weeks ago and thought about all of the above issues and how to change RT to deal with them.  Lets forget the policy discussion because that still has to happen and even after it does if all of the above procedures are taken care of, there are still going to be issues monitoring and mis-assigning tickets, and everyone will still have the job of assigning and taking ticket from the various queues to deal with.

What if something could be built to analyze a ticket when it came in and determine the best person to assign it to.  That simple sentence, eliminates the two major issues above, monitoring and (mis)assigning.  Sounds like a job for some machine learning, or keyword relevance, or context analysis, or a mixture of all three.  How difficult would it be to build a plugin for RT, or bolt on something to analyze and route tickets properly.

I bounced this off of a few other people here, including a couple professors, one of which I took an Artificial Intelligence course from.  They loved the idea and both wished their summers were free to help built it 🙂  I do have their support to hit up for help.

RT is the perfect application to try this with too, because it can operate using email.  Here’s the concept –

Anytime a new ticket comes into RT, an email with all the ticket information is sent to a special address setup for this.  The analysis system monitors that mailbox and pulls in new emails, analyzes them and determines whom the ticket should go to.  Currently this analysis is a black box, and could contain any set of rules, logic, Natural Language Processes, etc.  Email goes in – best match(es) come out.

At first this system, we’ll call Sherlock (because he’s awesome), will analyze a ticket and come up with the person or persons it thinks is a good match.  It will email those people on its own, not using RT, to alert them to the new ticket it thinks falls within their expertise.  The email contains a link to the ticket, a couple response links, and a “Pandora – why did I get this” section that shows the rules it used to determine why it thinks this is for them.

For example, lets say a ticket came in and Sherlock deduced that Bob and Jon may be potential owners. Bob and Jon both get emails with a link to the ticket.  They click the link and view the ticket in RT.  If this indeed is correct and they should be the owner, they click the “yes this is correct” link/button in the email message and that is used to reinforce the rules Sherlock used.  If this has nothing to do with them, they click the “no, this is not correct” link and conversely this downgrades the rules used.  The no link can also (if desired by the user) ask 2 more questions –

  1. who should this ticket be assigned to
  2. what keywords or phrases can help me process this better in the future

Often times we as humans can read into text, get the idea of what the person means, realize that they called one system something else.  Maybe two or more systems are integrated and I can tell which one they’re accessing by the description of what they were doing, or by the URL or error message.  So asking #2 above will be helpful in teaching Sherlock those nuances.

Sherlock can be extended to actually request more information from the user before anyone ever sees the ticket (unless you’re one of the RT hawks that constantly lives in RT).  For example, a ticket comes in and someone says generically, I received an error when I was filling out the vehicle request form. We know that error could be anything, literally.  Sherlock could determine there is no error message in the ticket, nor a url and email the user back and request they paste in the error message and url.  This can be expanded and we can have Sherlock ask for a multitude of information we may need to fix the issue, when this information is also necessary to figure out who to route the ticket to.

Notice NONE of the above is not affecting RT at all. Its removed the nagging from group A, because now its a bot that is gently asking if this is yours, and if not you can help it learn why.  It alerts the “proper” people of new tickets, eliminating the constant monitoring of RT and reading many, many tickets that have nothing to do with you.

After a period of time, its accuracy should be pretty good, and with RT’s email interface, can generate an email back to RT and assign the ticket.  When doing anything to a ticket in RT, Sherlock will always add a comment to the ticket with its Pandora disclaimer, so you know why you were assigned.  That comment will also contain the yes/no links allowing Sherlock to be continually trained.

As I move forward with this project, I’ll use this blog to track my progress, and you can all view my successes and failures, and watch me learn all about NLP and content analysis, and who knows, maybe the system will make us one big happy family again.

 

Posted in AI | Leave a comment

Whoa. Its been a while

How are you doing?  It looks like its been quite some time since I’ve posted and people have asked me multiple times what I’m up to.

Here’s a quick rundown

I started the Jadu Developers Network, specifically for, well, um, Jadu CMS developers, yea I know, not really a creative title : http://jadudev.net

I’ve created a new product called conferenSpy, a type of concierge app for conference planners easing the mundane collection and maintenance of venue information, tracks, track leaders, presenters, presentation information, etc.   You can see a live session list for a past conference here Below is a screen shot of the main dashboard.

conferenSpy Dashboard

 

The best part is that its fully integrated into a mobile app for attendees to use throughout the conference.  Works offline and/or can sync automatically to update itself or on demand if necessary.

PABUG Home Screen PABUG Home Screen PABUG Slide Menu PABUG Floorplans PABUG About Screen

I’m also involved with SciTech High School in Harrisburg’s after school robotics program teaching kids to program using robotics.  The class is also involved in FIRST Robotics Competitions, and below is a picture of one of our bots climbing up “the mountain” and from one of the state qualifier competitions. You can see the mountain the bots have to climb.

robot climb  competition field Staging area

 

 

 

As a side project, I’ve built a home arcade system.  I LOVE classic arcade games, and now I can play anytime I want.

original cabinet side original cabinet control panel before buttonscontrol panel wiring  control panel buttons installed control panel installed

I had some guys over to play and realized that you couldn’t see the screen unless you were hovering over a shoulder.  For a couple people this isn’t a problem, but when you have 5 or 6 guys over to play, its fun to talk trash about whomever is playing at the time.  So I installed a 2nd monitor card and cloned the display 🙂

spectator monitor

I guess that’s about it for now.

 

Posted in Uncategorized | Comments Off on Whoa. Its been a while

PASFAA 2014 Conference App

pasfaa_01_splashI’ve completed work on this year’s version of a conference app for PASFAA.org‘s annual conference. This time around, I completely started over, built from the ground up to be a nice looking, functional and helpful app.

The focus this year was more on the attendee user, and exposing functions they would need to enhance their conference experience.  One of these key features with this release is a Up Next section on the home screen. This little gem is a rolling list of sessions happening at this moment and upcoming in the next hour.  If you happened to have bookmarked sessions you’re interested in, these are highlighted in this list, so you can always know where you need to be.  And along those lines, I’ve integrated floor plans as well.  From Session Details, you can tap and view the floor your session is located on.

The Conference Contacts is a cool new feature.  How many times you have you met someone at a conference, swapped business cards only to find out you lost it, or left it in the hotel room. The app solves this problem.  When you want to remember an attendee, you can find them in the Attendees list and add them to your Conference Contacts.  You can even send them a text or email message from within the app to arrange a lunch meeting.

As most conferences are, this one is highly sponsored, so PASFAA wanted banner ads for those sponsors at the bottom of a handful of screens.  This was fun to build actually because they continue to cycle all throughout the app.

So I mentioned this was built from the ground up.  since I was starting over, I wanted some new “hip” features like the slide menu, toast notifications, etc.  I decided to use Titanium Appcelerator’s MVC framework Alloy.  You can see from my past post in March, I was just starting out with Alloy, and in six months time, I learned enough to produce a complete app.  Actually, truth be told, it was a somewhat painful 6 months, even thought there is a lot if information on the web, it seems there are many proof of concept type apps, widgets and modules that aren’t really supported anymore.  So even if you found exactly what you wanted to add to your app, if it didn’t work, you were kind of on your own.

I also built this to sync with my server, so PASFAA admins can log in, add/edit sessions, attendees, notifications, and partners and they’ll get pulled down to the device.  More importantly- it also works offline because we have all experienced sucky / terrible / non-existent internet at most venues, so it was important for it to work under various conditions.

I’m pretty proud of this app and its functionality.  Its currently waiting at the App Store, and I’m struggling to get the Android environment setup and then I’ll push it to Google Play as well.

UPDATE:  They’re both live and available to use

Here’s my fun “little” app description :

Main Features:

Next Up!
Lets face it, you need to know where you’re going, before the next session starts. At a quick glance at the Home screen, you can view the sessions happening now, as well as the sessions coming up in the next hour. Your bookmarked session are highlighted so you can easily see where you’re headed, and change your mind if you get there and its not what you were expecting. This feature is priceless.

Works Offline!
We all know the internet connection at many venus isn’t the best, so this app works offline until you have a connection. All aspects of the app – sessions, attendees and notifications will all sit patiently until you’re connected. The next visit to that screen will connect and pull down any updates that may have happened. Chances are, there weren’t any, but if there were, we’ll grab ’em and update your lists.

Complete session Information
You want to know details about the session you’re headed to, and we want you to be well informed as well. Each session displays a plethora of information for you to consume including the date and time of the session, presenter information, a full session description, and a link to the proper floor plan. Pretty convenient. You don’t have to remember if Royal III was on the first or third floor, just tap the link and the app will show you.

Bookmark your sessions to build your own schedule
Its always nice to have your days setup, and you can do this with the app. Just view the session details, and tap Bookmark Session and it’ll be added to the My Sessions screen, and will also be highlighted in the Up Next section on the Home screen.

Which Floor?
Each session details screen links up to the proper floor plan to help you find where your next session is. Floor Plans can be paned and zoomed to quickly scan for your room.

Attendees and Contacts
– Have you ever met someone at a conference, exchanged cards only to lose it later? Just find the attendee in the app, and add them to your Conference Contacts. From here you can send them an SMS during the conference to meet up for lunch, or send them an email.

This app was built with you, the conference attendee in mind, and will aid in your enjoyment help you get the most out of the conference.

Available In the App Store google-play-logo

In the meantime, you can drool over the screenshots that I’ve prepared for the stores.

To report bugs or support needs please : contact me

pasfaa_01_splash pasfaa_02_home pasfaa_03_slidemenu pasfaa_04_floorplans pasfaa_05_about

And of course – an app is not complete unless it has a Quick Tour to explain how it works, so I’ve included one of those as well.

step1 step2 step3

Posted in Appcelerator | Leave a comment

Titanium Alloy Newbie –

I’ve started playing with Titanium Alloy from Appcelerator.  There are some things that most tutorials don’t cover, and as I struggle through learning this I’ll post what I’ve learned.  Yes, these may seem silly once you know what you’re doing, but hopefully it may help someone learn this a bit more quickly.

Once I installed Studio and upgraded to the latest SDK (3.x), from the Getting Started panel, you can scroll down and perform a one click install of some sample apps.  I chose the ToDo list to play around with.  If you do this, be sure to choose the one for Alloy because there is also a ToDo list for commonJS (standard Titanium I call it)

I ran the app to see what it does, and then started looking at the code. At first I thought it was multiple screens and saw the header block in index.xml and thought that was pretty inefficient. After looking at the other files, I realized I was wrong and just has some slide up views.  If it did have multiple screens, I may want to include the same header on each screen.

Why would you want to do this?  I had, in the past, built an app that had the client’s logo in the header of each screen.  That was built long ago with Rhomobile, and it did not allow you to modularize things like this, so I had a pile of duplicated code across the app, which is problematic if you had to alter it at all.

There wasn’t anything I found easily to tell me how to include other code, because I’m new and had no idea what to search/look for and didn’t know the terminology. I had no choice but to start messing around, examining other example apps, and snips of code.

What I found was the <Require> statement, which is a little further down in index.xml.  When I first tried this, I copied that line, changed it to header, and it didn’t work, go figure.  I’ve since found an example in the docs (I know, right?) that nudged me in the right direction.  That page is here ( http://docs.appcelerator.com/titanium/3.0/#!/guide/Views_without_Controllers ) if you’re interested.  I know I actually ended up needing a controller, but more on that in a bit.

What I ended up with was this :

<Require id='index_header' src='header' type='view' />

The id name is arbitrary, I named it index_header since it’s located in index.xml.  What is important is the src, and type.

I commented out the entire header view in index.xml and added the line above.  I copied that header view block into a new file, header.xml and placed that in the views directory. Now in my mind my index.xml is including my header.xml file – perfect.

Not so much.  You would hope this is enough, and typically it would be if it were a simple header, but this block of code allows you to click the + icon to add a ToDo item.  That icon you can see in the new header.xml file contains an onClick event.  Ends up I need a controller after all to deal with this onClick.  A controller is just a javascript file that has functions you’ll call.  These may be simple ones like the addToDoITem, or something more complex like syncing changes t a remote database.

To create the controller I needed, in the controllers directory, I created a file called header.js (to match the .xml file).  I opened the index.js file and copied the addToDoItem() function and I renamed the original one in index.js just to be sure there were no collisions.  At this point in my learning, I’m not sure if you need to do this, I’m guessing its safe to remove from index.js.

I ran it. I was closer but it didn’t look right. Ahh, the styles.

Screens are styled with a .tss file, so I also need to copy the classes that this header view references into a new header.tss file (again same name as my .xml file). I created a new file in the styles directory and move the various items to this file : #header, #title, .divider,#addImage,#addView and saved it.

I ran it and it ran with the header area now modularized.

The require statement is pretty useful, and if used properly can allow you to create some pretty modular code.

 

Posted in Alloy, Appcelerator | 1 Comment

Mavericks, XAMPP and Sendmail Oh My!

I develop web applications on my MacBook Pro.  I’ve recently upgraded to Mavericks and changed over from MAMP to XAMPP.  One thing that we all have to do at some point is create email notifications.  Whether that takes the form of a forgot password link, a verify email address link, or some other activity notification, typically a local development server install like XAMPP (on Mac) does’t do email out of the box.

If you search around, you’ll find a lot of differing ways to get XAMPP to do this.  I messed around with this for quite sometime, and was able to get a configuration that worked for me.

One caveat – you need to have a real live SMPT server somewhere.  I happen to be located on a college campus, and all email leaving the campus must run through that, so I’ve set up my machine to use that host.  The problem with this is – if I’m off campus, I actually have to VPN in, to send email.  So, this still isn’t perfect but its working for me at this point in time.  I’ll post back, when I have an independent solution setup, or if you have one, please feel free to leave a link in the comments, or even better, spell it out in the comments.

I got my start on this quest here – http://stackoverflow.com/questions/15965376/how-to-configure-xampp-to-send-mail-from-localhost The kicker with this first solution is that XAMPP for OSX doesn’t come with sendmail, so the part about editing sendmail.ini was useless, which essentially makes the post mostly useless to me and other mac users.

After digging around I managed to set up something that was crazy simple.

First back up the file we’ll edit –

cp /etc/postfix/main.cf  /etc/postfix/main_orig.cf

then edit it –

sudo vi /etc/postfix/main.cf

and set

relayhost = [smtp.theserver.edu]

you may be tempted to edit myhostname, or mydomain but just leave them commented out.

save the file

Back up your php.ini file –

cp /Applications/XAMPP/etc/php.ini  /Applications/XAMPP/etc/php_orig.ini

then edit it –

sudo vi /Applications/XAMPP/etc/php.ini

search for SMTP, it may be commented out, but change it to this –

SMTP=localhost

uncomment

smtp_port=25

then change

sendmail_path = /usr/sbin/sendmail -t -i

save the file

restart apache

and you should be able to send email.

I realized as I typed this that if the smtp server you’re using requires you to authenticate, you’ll need to do more postfix configuration.  Here is a link that walks you through setting up sendmail / postfix using Google’s smtp servers and authenticating with your gmail credentials

http://slashusr.wordpress.com/2012/02/14/enabling-postfix-for-outbound-relay-via-gmail-on-os-x-lion-11/

This would allow me to run my webapps locally and not have to VPN in to send email, which is preferable, so if I know me, and I do, I’ll probably go through this when I have some more time.

Whatever you decide, good luck.

 

Posted in PHP | Leave a comment