Merge remote-tracking branch 'github/master'

# Conflicts:
#	composer.lock
This commit is contained in:
Dave 2016-03-30 13:23:39 +01:00
commit beab5d64a5
17 changed files with 901 additions and 515 deletions

View File

@ -0,0 +1,114 @@
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Models\Attendee;
use App\Models\Event;
use Carbon\Carbon;
use Illuminate\Http\Request;
use JavaScript;
class EventQrcodeCheckInController extends Controller
{
/**
* Show the check-in page
*
* @param $event_id
* @return \Illuminate\View\View
*/
public function showCheckIn($event_id)
{
$event = Event::scope()->findOrFail($event_id);
JavaScript::put([
'qrcodeCheckInRoute' => route('postQRCodeCheckInAttendee', ['event_id' => $event->id])
]);
return view('ManageEvent.QrcodeCheckIn', compact('event'));
}
/**
* Check in an attendee
*
* @param $event_id
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function postCheckInAttendee($event_id, Request $request)
{
$event = Event::scope()->findOrFail($event_id);
$qrcodeToken = $request->get('qrcode_token');
$attendee = Attendee::scope()->withoutCancelled()
->join('tickets', 'tickets.id', '=', 'attendees.ticket_id')
->where(function ($query) use ($event, $qrcodeToken) {
$query->where('attendees.event_id', $event->id)
->where('attendees.private_reference_number', $qrcodeToken);
})->select([
'attendees.id',
'attendees.order_id',
'attendees.first_name',
'attendees.last_name',
'attendees.email',
'attendees.reference',
'attendees.arrival_time',
'attendees.has_arrived',
'tickets.title as ticket',
])->first();
if(is_null($attendee)){
return response()->json(['status' => 'error', 'message' => "Invalid Ticket! Please try again."]);
}
$relatedAttendesCount = Attendee::where('id', '!=', $attendee->id)
->where([
'order_id' => $attendee->order_id,
'has_arrived' => false
])->count();
if($relatedAttendesCount >= 1){
$confirmOrderTicketsRoute = route('confirmCheckInOrderTickets', [$event->id, $attendee->order_id]);
$appendedText = '<br><br><form action="'. $confirmOrderTicketsRoute .'" method="POST">'. csrf_field() .'<input type="hidden" name="_method" value="PUT"><div class="row"><div class="col-md-10 col-md-offset-1 col-xs-12"><button class="btn btn-primary btn-block btn-lg" type="submit"><i class="fa fa-ticket"></i> Check in other tickets associated to this order</button></div></div></form>';
} else {
$appendedText = '';
}
if ($attendee->has_arrived) {
return response()->json([
'status' => 'error',
'message' => 'Warning: This attendee has already been checked in at '. $attendee->arrival_time->format('H:i A, F j'). '.' . $appendedText
]);
}
Attendee::find($attendee->id)->update(['has_arrived' => true, 'arrival_time' => Carbon::now()]);
return response()->json([
'status' => 'success',
'message' => 'Success !<br>Name: ' . $attendee->first_name . ' ' . $attendee->last_name . '<br>Reference: '. $attendee->reference . '<br>Ticket: '. $attendee->ticket . '.' . $appendedText
]);
}
/**
* Confirm tickets of same order.
*
* @param $event_id
* @param $order_id
* @return \Illuminate\Http\Response
*/
public function confirmOrderTickets($event_id, $order_id)
{
$updateRowsCount = Attendee::where([
'event_id' => $event_id,
'order_id' => $order_id,
'has_arrived' => false
])
->update(['has_arrived' => true, 'arrival_time' => Carbon::now()]);
session()->flash('success_message', $updateRowsCount . ' other tickets checked in.');
return back();
}
}

View File

@ -562,6 +562,27 @@ Route::group(['middleware' => ['auth', 'first.run']], function () {
'uses' => 'EventCheckInController@postCheckInAttendee',
]);
/*
* -------
* QRCode Check In App
* -------
*/
Route::get('{event_id}/qrcode_check_in', [
'as' => 'showQRCodeChechIn',
'uses' => 'EventQrcodeCheckInController@showCheckIn',
]);
Route::post('{event_id}/qrcode_check_in', [
'as' => 'postQRCodeCheckInAttendee',
'uses' => 'EventQrcodeCheckInController@postCheckInAttendee',
]);
Route::match(['PUT', 'PATCH'], '{event_id}/confirm_order_tickets/{order_id}', [
'as' => 'confirmCheckInOrderTickets',
'uses' => 'EventQrcodeCheckInController@confirmOrderTickets',
]);
/*
* -------
* Promote

View File

@ -32,6 +32,8 @@ class Attendee extends MyBaseModel
'ticket_id',
'account_id',
'reference',
'has_arrived',
'arrival_time'
];
/**

View File

@ -25,7 +25,8 @@
"omnipay/paypal": "*",
"omnipay/bitpay": "dev-master",
"omnipay/coinbase": "dev-master",
"barryvdh/laravel-ide-helper": "^2.1"
"barryvdh/laravel-ide-helper": "^2.1",
"laracasts/utilities": "^2.1"
},
"require-dev": {

895
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -167,6 +167,7 @@ return [
Mews\Purifier\PurifierServiceProvider::class,
MaxHoffmann\Parsedown\ParsedownServiceProvider::class,
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
Laracasts\Utilities\JavaScript\JavaScriptServiceProvider::class,
],
/*

30
config/javascript.php Normal file
View File

@ -0,0 +1,30 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| View to Bind JavaScript Vars To
|--------------------------------------------------------------------------
|
| Set this value to the name of the view (or partial) that
| you want to prepend all JavaScript variables to.
| This can be a single view, or an array of views.
| Example: 'footer' or ['footer', 'bottom']
|
*/
'bind_js_vars_to_this_view' => ['Shared.Layouts.ViewJavascript'],
/*
|--------------------------------------------------------------------------
| JavaScript Namespace
|--------------------------------------------------------------------------
|
| By default, we'll add variables to the global window object. However,
| it's recommended that you change this to some namespace - anything.
| That way, you can access vars, like "SomeNamespace.someVariable."
|
*/
'js_namespace' => 'Attendize'
];

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
public/assets/images/down.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
public/assets/images/firefox.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,99 @@
body{
font-family: "Source Sans Pro", sans-serif;
}
a:active, a:focus, a:visited{
text-decoration: none;
}
a:hover{
text-decoration: underline;
}
#outdiv
{
width: 400px;
height: 250px;
margin: 0;
padding: 0;
}
#v{
width: 400px;
height: auto;
margin: 0;
padding: 0;
border: 2px solid #c5c5c5;
}
#qrfile{
border: 2px solid #c5c5c5;
width: 400px;
height: 250px;
}
#qr-canvas{
display:none;
}
#help-text{
z-index: 9999999999;
position: relative;
color: #00AEFB;
top: 0;
}
#imghelp{
position:relative;
left:0px;
top:-160px;
z-index:100;
background:#f2f2f2;
margin-left:35px;
margin-right:35px;
padding-top:15px;
padding-bottom:15px;
border-radius:20px;
}
.selector{
cursor:pointer;
}
#result{
border: 1px solid #eaeaea;
padding: 10px;
margin-top: 3em;
color: #456D86;
width: 50%;
background-color: #f2f2f2;
font-size: 1.5em;
font-weight: 500;
box-shadow: none;
border-radius: 3px;
transition: background 0.4s ease-in-out;
}
/* Mobile */
@media only screen and (max-width: 480px) {
#result{
width: 90%;
}
#outdiv{
width: 300px;
height: auto;
}
#help-text{
top: -35px;
}
#qrfile{
width: 300px;
}
#v{
width: 300px;
}
}

BIN
public/mp3/beep.mp3 Normal file

Binary file not shown.

1
public/vendor/qrcode-scan/llqrcode.js vendored Normal file

File diff suppressed because one or more lines are too long

153
public/vendor/qrcode-scan/webqr.js vendored Normal file
View File

@ -0,0 +1,153 @@
// QRCODE reader Copyright 2011 Lazar Laszlo
// http://www.webqr.com
var workingAway = false;
var gCtx = null;
var gCanvas = null;
var c=0;
var stype=0;
var gUM=false;
var webkit=false;
var moz=false;
var v=null;
var beepSound = new Audio('/mp3/beep.mp3');
var vidhtml = '<video id="v" autoplay></video>';
function initCanvas(w,h)
{
gCanvas = document.getElementById("qr-canvas");
gCanvas.style.width = w + "px";
gCanvas.style.height = h + "px";
gCanvas.width = w;
gCanvas.height = h;
gCtx = gCanvas.getContext("2d");
gCtx.clearRect(0, 0, w, h);
}
function captureToCanvas() {
if(stype!=1)
return;
if(gUM)
{
try{
gCtx.drawImage(v,0,0);
try{
qrcode.decode();
}
catch(e){
console.log(e);
setTimeout(captureToCanvas, 500);
};
}
catch(e){
console.log(e);
setTimeout(captureToCanvas, 500);
};
}
}
function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
function read(qrcode_token)
{
if(workingAway) {
return;
}
workingAway = true;
$.ajax({
type: "POST",
url: Attendize.qrcodeCheckInRoute,
data: {qrcode_token: htmlEntities(qrcode_token)},
cache: false,
complete: function(){
beepSound.play();
},
error: function() {
},
success: function(response) {
document.getElementById("result").innerHTML = "<b>" + response.message +"</b>";
}
});
}
function isCanvasSupported(){
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
}
function success(stream) {
if(webkit)
v.src = window.webkitURL.createObjectURL(stream);
else
if(moz)
{
v.mozSrcObject = stream;
v.play();
}
else
v.src = stream;
gUM=true;
setTimeout(captureToCanvas, 500);
}
function error(error) {
gUM=false;
return;
}
function load()
{
if(isCanvasSupported() && window.File && window.FileReader)
{
initCanvas(800, 600);
qrcode.callback = read;
document.getElementById("mainbody").style.display="inline";
setwebcam();
}
else
{
document.getElementById("mainbody").style.display="inline";
document.getElementById("mainbody").innerHTML='<p id="mp1">Attendize Checkpoint Manager for HTML5 capable browsers</p><br>'+
'<br><p id="mp2">sorry your browser is not supported</p><br><br>'+
'<p id="mp1">try <a href="http://www.mozilla.com/firefox"><img src="/assets/images/firefox.png"/></a> or <a href="http://chrome.google.com"><img src="/assets/images/chrome_logo.gif"/></a> or <a href="http://www.opera.com"><img src="/assets/images/Opera-logo.png"/></a></p>';
}
}
function setwebcam()
{
document.getElementById("help-text").style.display = "block";
document.getElementById("result").innerHTML='Scanning&nbsp;&nbsp;&nbsp;<i class="fa fa-spinner fa-spin"></i>';
if(stype==1)
{
setTimeout(captureToCanvas, 500);
return;
}
var n=navigator;
document.getElementById("outdiv").innerHTML = vidhtml;
v=document.getElementById("v");
if(n.getUserMedia)
n.getUserMedia({video: true, audio: false}, success, error);
else
if(n.webkitGetUserMedia)
{
webkit=true;
n.webkitGetUserMedia({video:true, audio: false}, success, error);
}
else
if(n.mozGetUserMedia)
{
moz=true;
n.mozGetUserMedia({video: true, audio: false}, success, error);
}
stype=1;
setTimeout(captureToCanvas, 500);
}

View File

@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<title>
Attendize QRCode Check In: {{ $event->title }}
</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700' rel='stylesheet' type='text/css'>
{!! HTML::style('assets/stylesheet/qrcode-check-in.css') !!}
{!! HTML::script('vendor/jquery/jquery.js') !!}
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
@include('Shared/Layouts/ViewJavascript')
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
$(function() {
$.ajaxSetup({
headers: {
'X-CSRF-Token': "<?php echo csrf_token() ?>"
}
});
});
</script>
{!! HTML::script('vendor/qrcode-scan/llqrcode.js') !!}
{!! HTML::script('vendor/qrcode-scan/webqr.js') !!}
</head>
<body>
<div id="main">
<header id="header">
<h2 class="text-center"><img style="width: 40px;" class="logo" alt="Attendize" src="{{ asset('/assets/images/logo-100x100-lightBg.png') }}"/><br><span style="font-size: 0.7em;">Check In: <strong>{{ $event->title }}</strong></span></h2>
</header>
<hr>
@if(session()->has('success_message'))
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3 col-xs-12">
<div class="alert alert-success alert-dismissible text-center" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<p><strong>Success</strong>: {{ session('success_message') }}</p>
</div>
</div>
</div>
</div>
@endif
<div id="mainbody">
<table class="tsel" border="0" width="100%">
<tr>
<td valign="top" align="center" width="50%">
<table class="tsel" border="0">
<tr>
<td colspan="2" align="center">
<div id="outdiv">
</div>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td colspan="3" align="center">
<p id="help-text">Put the QR code in front of your Camera (Not too close)</p>
</td>
</tr>
<tr>
<td colspan="3" align="center">
<p style="position: relative; bottom: -2em;"><a onclick="event.preventDefault(); workingAway = false; load();" href="{{ Request::url() }}"><i class="fa fa-refresh"></i> Scan another ticket</a></p>
<div id="result"></div>
</td>
</tr>
</table>
</div>&nbsp;
<footer id="footer">
<br>
<br>
<h5 align="center" style="color: #6D717A;">&copy; <a href="https://www.attendize.com/">Attendize</a> {{ date('Y') }} &middot; All Rights Reserved.</h5>
</footer>
</div>
<canvas id="qr-canvas" width="800" height="600"></canvas>
<script type="text/javascript">load();</script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
</body>
</html>