Blog List

William

Why designers should use Revision Control like Git

Revision control is not just for coders, it never has been, but this is a misconception that a lot of designers people have.

Revision Control is for EVERYONE!

Coders, designers, asset managers, copywriters, your boss and anyone else on your team who does anything related to FILES.

FILES, FILES, FILES

Really that's all Revision Control is about, files. What else do you use to create web-sites? A plank of wood? Unlikely.

You're already managing files with cloud storage, your local drive, network drive, remote drive, or some drive - somewhere - has your files on it. 

With all those options where are the files?

O Files, files! wherefore art thou Files?

Without a central repository to manage all of your code, assets and design, where do you look for them? They could be anywhere, if your team is anything like mine you may have your files in some of these locations:

  • The designers computer/my cloud/dropbox
  • The designers assistant(s) computer/my cloud/dropbox
  • The copywriter(s) computer/my cloud/dropbox
  • The asset manager(s)  computer/my cloud/dropbox
  • SVN (yay!)
  • Github (super yay!)

How do I find a file? I have to ask!

That's right, with 14 possible locations for the files to be located I must ask the last person I know who used them for the location

If we had a better way there would be some structure and a central location where I could easily find these files, by searching or just simple browsing.

Wait, there is a better way!

Of course there is, there has been for a very long time. I first started my Revision Control path around 2005 with CVS. It was quite amazing but was quickly replaced when I found SVN. Hooks and tons of other features pushed SVN to the top of my list until.. Github!

I started using Github as an individual but after working on several projects that utilized it I began to enjoy its features and how it makes managing your projects that much easier. Now I make sure any project I am working on uses it and the teams adopt it, once they do people often see how important it is to have such an amazing tool.

It's much more then Revision Control

Sure maybe that's a key part of it - but there is plenty more it provides you.

  • Central location for your projects files: since 14 locations is stupid
  • Backups: good luck loosing your files
  • Ability to share files with anyone: let your people access your stuff
  • Access Restriction: control who does what
  • Change logs: see wtf people are doing
  • Commit time tracking: see if/when employees are working
  • Bug Tracking/Wikis/Readmes: make it easy to document your work and track issues/todos

I could go on, there are dozens of new abilities you can implement with coding but we're here to talk about designers (and asset managers/copywriters), not coders.

Designers? Github? Git outa here

Those PSD files are huge! Githubs for code!

Github thought about that in 2015 and they released git-lfs enabling you to offload larger files, like PSD files, to a Large File Storage server.

Along with this feature they enabled PSD previews (for what seems to be an 80M limit), pretty awesome (if you're designer can get those sizes down). A simple jpg in the folder goes along way as well since even a 50M Photoshop file can take several seconds to load a preview.

That's cool and all...

But none of that matters - lfs just fancy talk and the preview of a psd (vs jpg) is just a modern luxury that still needs some work (they're better off pre-rendering jpgs..).

What matters is Revision Control! Central file location, access control, knowing where to go and what to look for - or being able to search one location to find out what you need. Pretty much what I've been saying but theres other things to consider like..

What if you die or quit?

Or hit the Powerball or what ever possibly could take you - and maybe your files - away from your job. Sure, when working for yourself this isn't a big deal but when your work belongs to the Company - it's a big deal to them.

Having a central repository ensures your work will be available to your Company and your team, allowing them to continue working during your vacation (since you're not likely dead yet). Since there is no confusion over the history of your files or where they are you wont be getting random e-mails or calls during your time off.

Your Boss will love it, but maybe you wont (if you're not productive)!

A big sell to the Boss, aside from backups and the ability to quickly revert changes, is the ability for them to review peoples work activity.

If your job is mostly related to managing files, design, asset management and coding, then you will likely commit changes very often (coders about every 20-30mins, designers 1-2 hours, asset managers on/off all day).

This lets the boss checkup on your activity, read your logs - see what's being done, track goals and basically get a feel for how productive the team is as a whole.

Committing work is proof that work is being completed.

It's hard to get called out for not getting work done when you can just look at the log and see how much you committed, me being a coder it's quite a bit - using SVN/Git to push to staging/production servers also forces my hand to commit changes more often (so I can see them).

As a designer or asset manager you can push commits after every major change, save, hour, automatically or manually so the process can be pretty painless. 

It took me a while to get used to pushing all my changes but after a couple weeks it felt natural and made total sense - make a big change - save a copy incase I screw up or loose it.

Did I mention it's a backup?

I've gotten rid of all my backup drives. I used to offload my important assets to all types of drives and servers. Now I send it to Github or my SVN repository and keep it synced on my PC/Laptop.

This gives me at least 3 locations for my code to be - not to mention whatever type of redundancy Github is offering - I no longer waste time thinking about it or worrying about what drive had what.

Oh, and Cloud Storage?

You'll have access to all these amazing features ANYWHERE you are that's connected to the internet (and that's just about everywhere now). New computer? BAM get all your files back lickety split. Friends computer? New job? 100's of reasons Cloud Storage is good for the team. 

It does suck when you're internet is slow - but optimize your techniques - get sizes down - and every ones life (including the accountants) will be better.

It's perfect for team work

Sure it's good if you're not on a team - but it's perfect if you are. 

You push - they pull, modify, push -  you pull.

We could complicate this a few steps more by adding branches and tags but let's keep it simple.

It's a few more steps then normal but now we know what was done and we have a history to go back incase we dislike the change. We can lock files to ensure others don't work on things when we are - and it controls the latest revisions to prevent you from ruining some ones hard work with your latest changes

It also helps reduce file clutter. It's not uncommon to see revisions stored in file names, File-a-rev1, File-a-rev2. This is not easily followed or managed by other members, so what goes great with Revision Control?

Did I say Structure earlier?

I'm pretty sure I did because it's a critical part to making this all work, lets take an example of "revision controlled" files when a human does it:

  1. Site-01-Page-abcd.psd
  2. Site-02-Page-abcd.psd
  3. Site-04-Page-abcd.psd
  4. Site-05-Pageabcd.psd
  5. Site-10-Page-abcd.psd

If you're a coder

  • file-name
  • file-name-
  • file-name0

Really it's like that.

We're human. We're lazier then computers and often make more mistakes when typing - so why do we even try to create our own human revision control system? 

Leave it up to the computer

It's better at managing time and numbers. You come up with the name and folder structure and it'll do the rest.

File names and folders? They matter?

They most certainly do! If you're using random folders, on random drives - with very random names - what do you get? I dunno, but it's not pretty.

Following a simple folder and file naming convention can help everyone on your team locate what it is they need.

An example of a structured setup would be:

  • /Website.tld/slug/desktop.psd
  • /Website.tld/slug/mobile.psd
  • /Website.tld/slug/tablet.psd
  • /Website.tld/slug/assets/(resources from asset managers)
  • /Website.tld/slug/copy/(resources from copywriters

Now we know where to find what page - there is no guessing, it's just like our website! Stick this in the repository along with your source code (that has routes and functions and the lot matching the exact same names) and you've just gained access to see everything related to a specific page with a simple search. That's awesome.

 

Conclusion

Revision control is wonderful. It's saved me in many different ways from quick reverts to total drive failures that would have lost everything I've worked on. If it wasn't for a revision control system I wouldn't be where I am today so I owe quite a bit to it.

It's a must have when working with a team

2 reasons for me: central file location & search. I can't search 14 drives for the file - that has some random name - but I can search 1 resource and file names based on known factors - something manageable - something everyone can do.

It's not just about me

It's about the next person. If you plan to stay at your job till you die, that's great. I don't. I want to be sipping cocktails on the beach long before I die - so I must leave something for the next person. Will I leave them a cluttered mess that's impossible to follow? I won't. I'll leave a well thought out, structured and documented method that anyone with internet skills could understand. 


  0
William

Laravel 5.2 Creating a New User

I recently started a Analytics program in Laravel 5.2 and was very pleased to find the auth system back in play and extreamly easy to use.

It didn't seem to come with any database seeders or commands to add users but seeding is nothing magical and the docs even had a great example.

Creating a user in Laravel 5 with a Seed File

Not to hard, you could use the docs example - or if you're like me - you just want a quick copy/paste to add a user with the details you've defined, so here it is:

UserSeeder, add a user to the users table.

Create a seed file in database/seeds, like database/seeds/UserSeeder.php.

<?php

use Illuminate\Database\Seeder;

class UserSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('users')->insert([
            'name' => 'admin',
            'email' => '[email protected]',
            'password' => bcrypt('password'),
        ]);
    }
}

Update your autoload

composer dumpautoload

Run artisan to add the new user to your database

php artisan db:seed --class=UserSeeder

 

Conclusion

I'm super happy the auth system is back in 5.2, it looks good - works well - just needed to seed a user and I'm logged in. It'd be nice to write an article with a seed command, so maybe later!


William

Selecting the right beacon for your IoT project!

I've recently started on a project that belongs to the Internet of Thigs, IoT, and it requires some proximity tracking - and for that the standard these days is BLE, or Bluetooth Low Energy, in the form of a 'beacon'.

Over the past year many new products have been released, more beacons, more software, just more of everything.
 

TL;DR

Beacons are beacons.

  1. $14 Radbeacon Dot
  2. $90 Estimote 
  3. $30 TrackR Bravo

All Beacons Are Different, but the same.

I've tested 3 beacons and each one is completly different. From battery size to chipset selection and of course, how it's packaged.

The one thing all 3 of these beacons shares is the iBeacon protocol. This means very little to me, since I'm just doing proxmitiy, but it's good to see the protocol being accepted. Hopefully more will be using AltBeacon instead, since it's truely open, where Apple.. is something you eat.

Let's review a little bit about the ble beacons I've tested. 

Estimote

This was the first becon I received. I orignally chose Estimote because out of the few I found, they seemed to be the most popular and had decent resources for developers.

I received my beacons in a few days and immediatly cut one open to check it out. I found a few things out:

  1. Replacing the battery requires you to destroy the case
  2. The battery is massive.
  3. The board is also massive
  4. Editing the beacon requires you to be online and have the beacon associated with their API
  5. You can't buy just 1 beacon, only sets of 3, and the'yre very expensive. $30 a unit is over-priced

Overall the Estimote was not that good. Sure, its a regular beacon, you can actually edit it's settings, use their API, but there was nothing to hold me to it, I quickly started looking for better alternatives that did not come with an ugly case.

I'd pass on the Estimote, unless you want their so-called indoor location tracking. We're really waiting for their stickers, then it will be worth checking out again.

Pros:

  1. Largest battery of the 3, should last a long time, advertised up to 3 years
  2. Good for developers
  3. Good if you want to use their location or proximity apis

Cons:

  1. You'll have to cut the case open to replace the batterys
  2. Batterys do not come fully charged
  3. Editing settings requires internet connection and logging into their software

Rating:

It could be better. There are a lot of things that can be improved on this design, for developers and consumers.

I was disapointing in the Estimote.

 

The TrackR Bravo

Let me start by saying I actually know the creator of TrackR, so I may be a little biased - but probably a bit more harsh.

We received a few TrackR Bravos for free directly from TrackR, retail they're going for around $30, the same as the Estimote, but you can buy 1 at a time. I like this. 

This beacon is not made for developers but is an actual product, to find lost items and what not. My project only calls for proximity tracking so any 'extra' features are not something I cared about, looking only at RSSI stength made this device work just fine.

 

  1. The smallest form factor of all 3
  2. Super tiny battery, probably wont last to long
  3. Not really for developers
  4. Has a 'call' button that floods its ping rate
  5. Can buy one at a time

I tested a couple of these for a week and found them to be on-par with the rest of the devices, they're super small and that's pretty impressive. Batterys are easy to replace and the call back button was a nice added feature.

Pros:

  1. Can buy 1 at a time
  2. Easy to replace battery
  3. Super small form factor
  4. Push button call back

Cons:

  1. No developer resources
  2. Both beacons stopped pinging after 3-4 days, so may not work for constant proxmity tracking
  3. Cheap case

 

Rating:

It's ok. I liked how small it was, easy to replace the battery, call back feature was nice. It'd be my beacon of choise for this project if both beacons didn't stop reporting after a few days. I was scanning them perfectly fine every second or so and one day - bam - one stopped reporting. A day later, the second one stopped as well. Pushing the call button sends out pings, but after that - nada. I haven't gone back to check, maybe its some feature - maybe not - but in either case this project needs something that is constantly pinging - and never stops.

 

Radbeacon Dot

After testing the first two beacons I found the Radbeacon Dot by Radiusnetworks. At $14 this was very affordable and fit perfectly within the projects budget. A few days after ordering a batch of 10 arrived and I was able to quickly get started.

This beacon is made for developers. They provide a few apps and some APIS. I didn't check out the APIs and the apps, like others report, did not work very well. 

It has a button to turn the device on and off and a medium sized battery so it should last quite a long time. The board itself is quite large, not very well optimized and looks to be closely based on the nRF51822s hardware.

Pros:

  1. Cheap!
  2. Good sized battery, easy to replace
  3. Great for developers
  4. Can turn on/off
  5. iBeacon and Altbeacon compatible

Cons:

  1. Apps to configure the devices we're not good, many reviews indicated this before I even tried, but I think it worked, not much to configure anyway.
  2. Large form factor, clutterd board - it has got to use more power then other devices
  3. Cheap case

Rating:

It's the best of 3. But I am still looking for alternatives. This beacon, overall, is good. It is the best one for developers and will last a long time. They provide all the same API crap as everyone else, same settings and more compatiblitiy. I don't like the on/off switch, nobody else has em and are something we can't have in this project. Sure we'll just disable the switch but then we have to mess with having a large form factor and a poorer design.

If you only had these 3 to pick from - choose the dot - its the cheapest, does regular beacon stuff, and won't let you down.

 

Conclusion

BLE Beacons today suck. I've yet to find any beacon that has everything I need for this project, sure they all would work but that's not the point. There isn't even that many of them out there. Most BLE devices seem to be in watches or wrist bands, but just for Beacons I think that world is still growing, so it's a bit to early to be so picky.

What would my perfect beacon be? Something simple:

  1. Replaceable, mid sized, battery
  2. Small form-factor
  3. Optimized hardware for the lowest power consumption
  4. A quality case
  5. Configurable settings

​Buy any of the 3, it's hard to go wrong, but if you're a developer - and on a budget - pick the Radbeacon Dot. It's price is great, it works and has some resources if you need em. 

 


  1
William

Python Read Proc File, Check PID, Control Service

Soo one of the startups I am working on has gotten me into some Python. I've never played with this language, beyond changing a few lines here or there for some system crap, so this is a new experience.

But just like learning Ruby with Sinatra, I go based on examples and Python being an old ass language has plenty of those.

Basic Service Management with Python

I was after just that, something simple. I'm using daemon-py to run a couple Python scripts and wanted to give my simplehttpserver some control over them.

So what do you need do? Only a few things, most apps - including ours - will write a pid file. So we check it, check the id in it and do some shit right?

  • Check if pid file exists
  • Read it
  • Check if process is running
  • Do some shit

Let's check that pid

So we know the pid file, let's read it, if it's got a pid - check that mother fucker too, then we really know the deal.

 

def pid_exists(pid):
  import errno
  if pid < 0:
    return False
  try:
    kill(pid, 0)
  except OSError as e:
    return e.errno == errno.EPERM
  else:
    return True

def check_proc(pidfile):
  if path.isfile(pidfile):
    stats_pid = open(pidfile)
    pid = int(stats_pid.read())
    if pid > 0:
      if pid_exists(pid):
        return True
      else:
        return False
    return False
  return False

It's not to difficult to read a file and check if a process exists in Python. 

Pretty easy to trigger services too, or whatever the fuck you do to control your crap.

Do Some Shit, Restart a Service

That's all I wanted to do. Pretty simple since we use daemon-py.

def control_service(name, control):
    command = ['python', name, control];
    subprocess.call(command, shell=False)


control_service('myscript.py', 'restart')

 

Conclusion

A language is a language. Python, whatever, it's neat, pretty easy, lot's of resources. The indents drive me nuts, but they're cool at the same time.

So far this month I've done PHP, Ruby and Python. Moving forward with one startup I need to decide what direction we'll take. So far it's been a Python based program, but that's cause we're running an  Intel Edison and Python is a default language. 

I went back to look at Laravel and started using Eloquent and was greatly disappointed after using Rubys Datamappers. The ability the design your database, and relations, was extremely easy, making Eloquent look like utter shit. I did find some Datamapper PHP ports, but nothing like the original.

 


William

jQuery Bootstrap HTML2Canvas Bug Feedback Reporter

TL;DR

Check out the demo.

Check out the github repo.

Update

Some people asked for example on sending the mail, we'll sending mail has a lot of choices, so that's up to you - but view the updated report.php for everything you need to send the mail.

I can read a little..

So I've been using UserVoice for over a year now, it's not so good - but it was free, so I can't complain to much. I wanted a way for my customers to provide feed back in my applications, I didn't want to write something at the time and most the solutions cost something or were crap.

I noticed NodeQuery and a few other sites were using UserVoice so I figured it was legit.

I have enjoyed the service but its time to bring everything back in house. I'm using their widget on a SaaS application and don't want them having access to my clients browser but I still need site feed back. Bugs at this time, it's a fresh release, but later on things like comments, suggestions, even user voting on ideas.

Gotta be bootstrap

Everyone's still doing bootstrap so I'll do it too. It's way better then what jQuery UI ever was (it's still being used?). UserVoice had a decent theme, it matched, but nothing like the actual theme you're already using - that is bootstrapped right?

Now UserVoice gives you a lot more options, all the fancy crap - I want it, but today I just want simple bug reporting so here it is.

Not to bad.

Making It A Plugin

PLEASE NOTE: Code below is older then the github repo.

Why not? The core of any version of this only does a few things, lets do that and then you can write your own html. Later we can add callbacks so you can do some fancier shit but for not it's pretty simple.

(function ( $ ) {
    $.fn.feedback = function() {
    self=$(this);
    $(this).find('.dropdown-menu-form').on('click', function(e){e.stopPropagation()})

    $(this).find('.screenshot').on('click', function(){
      $this=$(this);
      $this.find('i').removeClass('fa-camera fa-check').addClass('fa-refresh fa-spin');
      html2canvas($(document.body), {
        onrendered: function(canvas) {
          $('.screen-uri').val(canvas.toDataURL("image/png"));
          $this.find('i').removeClass('fa-refresh fa-spin').addClass('fa-check');
        }
      });
    });

    $(this).find('.do-close').on('click', function(){
      self.find('.dropdown-toggle').dropdown('toggle');
      self.find('.reported, .failed').hide();
      self.find('.report').show();
    });

    $(this).on('submit', 'form', function(){
      $.post( $(this).data('action'), $(this).serialize()).done(function(){
        self.find('.report').hide();
        self.find('.reported').show();
      }).fail(function(){
        self.find('.report').hide();
        self.find('.failed').show();
      });
      return false;
    });
  };
}( jQuery ));

$('.feedback').feedback();

And it's gotta look decent

.btn-circle.btn-lg {
  width: 40px;
  height: 40px;
  padding: 5px 8px;
  font-size: 12px;
  line-height: 1.33;
  border-radius: 25px;
}

.feedback{position: fixed;}

.feedback textarea{height: 180px; }
.feedback .screenshot{ position: relative; top: -24px; right: 10px; opacity: .6}
.feedback .screenshot:hover{  opacity: 1}
.feedback .reported p, .feedback .failed p  { height: 190px}


.feedback.left{left:5px; bottom:5px}
.feedback.right{right:5px; bottom:5px}

.feedback .dropdown-menu{width: 320px;height: 320px;bottom: 50px;}
.feedback.left .dropdown-menu{ left: 0px}
.feedback.right .dropdown-menu{ right: 0px}

And you sorta need the html

    <div class="feedback left">
      <div class="tooltips">
          <div class="btn-group dropup">
            <button type="button" class="btn btn-primary dropdown-toggle btn-circle btn-lg" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
              <i class="fa fa-bug fa-2x" title="Report Bug"></i>
            </button>
            <ul class="dropdown-menu dropdown-menu-right dropdown-menu-form">
              <li>
                <div class="report">
                  <h2 class="text-center">Report Bug</h2>
                  <form method="post" action="report.php">
                    <div class="col-sm-12">
                      <textarea name="comment" class="form-control" placeholder="Please tell us what bug or issue you've found, provide as much detail as possible."></textarea>
                      <input name="screenshot" type="hidden" class="screen-uri">
                      <span class="screenshot pull-right"><i class="fa fa-camera" title="Take Screenshot"></i></span>
                     </div>
                     <div class="col-sm-12 clearfix">
                      <button class="btn btn-primary btn-block ">Submit Report</button>
                     </div>
                 </form>
                </div>
                <div class="reported text-center collapse">
                  <h2>Thank you!</h2>
                  <p>Your submission has been received, we will review it shortly.</p>
                   <div class="col-sm-12 clearfix">
                      <button class="btn btn-success btn-block do-close">Close</button>
                   </div>
                </div>
                <div class="failed text-center collapse">
                  <h2>Oh no!</h2>
                  <p>It looks like your submission was not sent.<br><br><a href="mailto:">Try contacting us by the old method.</a></p>
                   <div class="col-sm-12 clearfix">
                      <button class="btn btn-danger btn-block do-close">Close</button>
                   </div>
                </div>
              </li>
            </ul>
          </div>
      </div>
    </div>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>

Wrapup

So ya, 30mins, it's pretty simple but loads instantly, has no branding, doesn't use a 3rd party - it's what I need for now. You can easily modify the HTML and CSS keeping the JS and make it submit just about anything in a fancy popup, well, dropdown (up) menu.

 

Enjoy!


William

Building a Multiple Location Cloud Hosting System

And on CHEAP VPS's!

I recently build a multi-national cloud node on 1-2gb ram vps's, it tested at over 1,000 concurrent users and I was very happy. The requirements were small and the budget was the change in my couch.

 

Today's Goal, A seperate "cloud"

I have been spending $50 per month for the past 5 years on my Co-located server. There are many reasons I co-locate, mostly security, but today my concerns are not as strong as before. The VPS providers I've selected are all of top notch quality, I do trust them - to an extent - and the data I am providing with my new software is not as sensative.

You can see my current VPS setup on my co-located server, they're all minimal specs (I have a whopping 6gb of ram) with 40GB disc space. I could host this, with 3x more space, for $36 at ServerHub. That's if I even needed that much. My main web-server and license server only use 400M of memory each.

So today, for $3 at ServerHub, I'll use their 512M package to get setup and later, for $6, upgrade it to the 1gb package. I can then roll out more 'nodes' later on, we'll start with one today and add another later.

 

Getting the VPS

Today I decided to use the $3 VPS at ServerHub, it's perfect to get started. Cheaper then DigitalOcean and is pretty decent.

You can pick any VPS you want. We're going to be using Debian 7. You should too, it's awesome.

Once you've acquired your VPS go ahead and login to ROOT SSH, that's where we will start next.

First things first, clean up and update

I don't like having extra crap installed. It takes up disc space, it's not secure and in general its just dumb. I typically build my servers from a minimal install but todays providers like to offer up servers with pre-loaded software, at least the web-server bits.

I don't want that crap, so lets get rid of it and update.

apt-get -y remove sasl2-bin apache2 bind9 samba sendmail-bin sendmail
apt-get update
rm -rf /etc/apache2/ /var/log/apache2/

Installing the base tools

Now I need my base tools, I like nano (not vi) and we need some crap for the deps

apt-get -y install nano python-software-properties software-properties-common --force-yes

Upgrading the Distro

I like to make sure I'm updated before I get started

apt-get -y upgrade

Adding Repos

We're not doing standard shit here so we'll need some repos to get us the tools

add-apt-repository 'deb http://mirror3.layerjet.com/mariadb/repo/5.5/debian wheezy main'
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db
apt-get update

Installing it all

Now we want to install the software we'll be using, Lighttpd, Galera, PHP5, PHP5-FPM, fun stuff

apt-get -y --force-yes install  ntp lighttpd python python-mysqldb perl python-software-properties rsync php5-fpm php5 php5-mysql php5-xcache unzip php5-curl php5-gd lighttpd-mod-magnet iptables-persistent php5-dev make php-pear perl python-software-properties rsync galera-3 mariadb-galera-server-5.5

Enabling some mods

We need to tell lighttpd and php about some stuff we just installed

lighttpd-enable-mod evasive
lighttpd-enable-mod fastcgi
lighttpd-enable-mod fastcgi-php
php5enmod xcache
php5enmod mysql
echo "cgi.fix_pathinfo=1" >> /etc/php5/fpm/php.ini
nano /etc/lighttpd/conf-available/15-fastcgi-php.conf

Redefine the fastcgi settings to use your fpm

fastcgi.server += ( ".php" =>
        ((
                "socket" => "/var/run/php5-fpm.sock",
                "broken-scriptfilename" => "enable"
        ))
)

 

That's it for now!

Restart your services and you should have a basic configuration that's ready for the next steps for our cloud hosting system.

Later on we'll talk about Galera Cluster and how to configure your web-sites to work on multiple nodes.


  0

William

CKEditor 4 Image Upload Button using an iframe.

I recently decided to switch to CKEditor 4 because TinyMCE just wasn't cutting it anymore. It was very for pasting code and always screwed up my html.

CKEditor 4 is much better then 2 and 3, the versions I've used, it's fast, prettty, works with bootstrap, inline editing, code snippets. But Image Uploading was not that easy to figure out.

CKEditor 4 Upload Image Button

Since the only solution I could find were a paid ones I decided to write my own. It wasn't that hard to write one for TinyMCE, just a simple hidden form to do the dirty work. We could be using ajax or some other fancy methods but the idea here is to be simple, it's not a big deal.

Download on Github

<script src="/ckeditor/ckeditor.js"></script>
<script>
  CKEDITOR.plugins.addExternal('imageupload', '/ckeditor/plugins/imageupload/', 'plugin.js');
  var editor = CKEDITOR.inline('editable', { extraPlugins: 'imageupload' });
</script>
#/ckeditor/plugins/imageupload/plugin.js
var action = '/admin/create/upload';
var field  = 'upload';

CKEDITOR.plugins.add( 'imageupload', {
  icons: 'imageupload',
  init: function( editor ) {
    editor.addCommand( 'imageupload', {
      exec: function( editor ) {
        $('body').append('<div id="upload_container_ck"><iframe name="upload_frame_ck" id="upload_frame_ck" style="display:none"></iframe><form method="post" action="'+action+'" target="upload_frame_ck" id="upload_form_ck" enctype="multipart/form-data"><input type="file" name="'+field+'" id="upload_file_ck" style="display:none"></form></div>');

        $('#upload_file_ck').trigger('click');

        $('#upload_file_ck').change(function (e) {
          $('#upload_form_ck').submit()
        });

        $('#upload_form_ck').on('submit',function(){
          $('#upload_frame_ck').on('load', function(){
          var image=$('#upload_frame_ck').contents().find('body').html();
          editor.insertHtml( '<img src="' + image + '">' );
          $('#upload_container_ck').remove();
          });
        });
      }
    });

    editor.ui.addButton( 'Imageupload', {
      label: 'Image Upload',
      command: 'imageupload',
      toolbar: 'insert'
    });
  }
});

You can see we add a button, when clicked we add a form to the body, trigger a click on the file, you select file, the form is triggered, the iframe is read when its loaded and bam, you have your image.

It's that simple.

Accepting The Upload

By default the form will post to /admin/create/upload with a field named upload so you'll use your backend language to read the file being uploaded and send back the url.

After uploading have your backend echo the url to the image.

Here is my example in Sinatra:

  halt 500 unless !params['upload'].nil?
  accepted_formats = [".jpg", ".png", ".gif"]
  halt 500 unless accepted_formats.include? File.extname(params['upload'][:filename])
  image='public/assests/images/' + params['upload'][:filename]

  new_image = File.open(image, "wb") do |f|
    f.write(params['upload'][:tempfile].read)
  end

  "#{image}"

 


William

Sinatra Simple Role-based access control RBAC

Every blog needs permissions and roles if you want to have more then a couple users managing it. Trusting random strangers is not good when it comes to your data so we shouldn't let them have access to some important things.

I google searched for "datamapper roles permission" and found this post that lead me to learn about RBAC another term invented to describe something I've always done, awesome! Fresh tags :D

I first ran into this article that seemed to have the start of something, but wasn't complete in any way. So the search continued and I figured I would just try to make it like I normally would, all examples seemed to show that's ok.

The Models

We'll use three models to set this up, Person, Role and Permissions. Roles will belong to Permissions and will be accessible by the Person, and Permissions will belong directly to the Person. This is neat, we can get get person.permissions and person.permissions.roles very easily.

class Person
   include DataMapper::Resource

   property :id, Serial
   property :slug, String   ,  unique_index: true, default: lambda { |resource,prop| resource.title.downcase.gsub " ", "-" }
   property :name      , String   , required: true
   has n, :posts
   has 1.0/0, :roles, :through => Resource
   has 1.0/0, :permissions, :through => Resource
end

class Role
    include DataMapper::Resource

    property :id, Serial
    property :title, String
    property :description, Text

    has n, :permissions, :through => Resource
end

class Permission
    include DataMapper::Resource

    property :id, Serial
    property :title, String
    property :description, Text
    has n, :roles, :through => Resource
    has n, :persons, :through => Resource
end

Making it work 

Last night I couldn't figure out how to properly update related data for tags and categories. It's still a bit borked, but that's for a fresh mind tomorrow. Tonight I managed to get the Permission manager to fully work, allowing you to assign roles and users to permissions.

Some simple ERB in my form that updates or creates the permission

<select id="permissions" multiple name="permissions[]" class="form-control">
  <% Permission.all.each do |perm| %> 
      <option value="<%= perm.id %>" <%= defined?(@person.id) && @person.permissions.include?(perm) ? 'selected' : '' %>><%= perm.title %></option> 
  <% end %> 
</select>

Then an example to update the assigned roles on a permission 

person ||= Permission.first(:id => params[:id]) || halt(404)
roles ||= Role.all(:id => params[:roles]) || halt(404)
person.update(:roles => roles)

And pretty much the same thing to assign permissions to persons

person ||= Person.first(:name => session[:username]) || halt(404)
perms ||= Permission.all(:id => params[:permissions]) || halt(404)
person.update(:permissions => perms)

Conclusion 

It was pretty easy to get a standard Permission and Role setup going in Sinatra with DataMapper. The next step will be to actually do something with those permissions and roles, like restrict access.

Update

Testing showed that new roles would not save, causing all roles to be unset. The solution was to scan the list (sent from select2) for numbers vs strings, new variables are strings, existing ones are numbers.

roles ||= Role.all(:id => add_missing(params[:roles], Roles)) || halt(500)

Then in my helper

def is_number?(object)
  true if Float(object) rescue false
end	

def add_missing array, model
  array.each do |r|
    if !is_number?(r)
    array <<  model.create(:title => r).id
    array.delete r
     end
  end	
  
  array
end

 Now the array being checked for roles will first be checked to see if we need to create a new role.

 I'm certain this can be better!

Looking at it more I'd guess I can extend the model to do this work, so maybe that's next.