#title No Act on ACT
#author Stefan Hornburg (Racke)
#SORTtopics ACT, Bootstrap, Dancer, DBIx::Class, Plack, Leaflet, XSRF, JWT, Jquery, Jcrop
#date 2016-09-21
#slides yes
#lang en
#pubdate 2016-09-21 10:00
#teaser Presentation about the pros and cons of the ACT conference system and our software written for the Perl Dancer conference.
** Conferences
*** YAPC::EU 2008 in Copenhagen
; The story starts with the first YAPC::Europe I visited 2008 in
; Copenhagen.
[[s-h-stefan-hornburg-racke-no-act-on-act-en-2.png]]
*** PerlDancer for Perlers (FOSDEM 2011)
[[s-h-stefan-hornburg-racke-no-act-on-act-en-4.jpg]]
[[http://www.slideshare.net/xSawyer/perldancer-for-perlers-fosdem-2011][Sawyer's presentation]]
*** Perl Dancer Conference 2014
; After all the fun we had, we decided to run our own conference on the topic
; of Dancer.
[[s-h-stefan-hornburg-racke-no-act-on-act-en-2.jpg]]
[[http://act.perl.dance/eic2014/]]
; You can imagine that we selected ACT conference software.
; Naturally, the conference was again a lot of fun.
** Using ACT in 2013/2014
; double-edged sword - personal contacts
- Managed software
- Listed in other conferences (Marketing)
- User database
** Modern Perl for web applications
- PSGI / Plack
- Web application framework (Dancer2)
- Web framework (Bootstrap, Jquery)
- DBIx::Class
- Moo and friends
- Testing
*** mod_perl vs PSGI
- Apache / mod_perl
- slow
- memory footprint
- deployment related code
- PSGI
- runs on any webserver supporting PSGI
- fast (Nginx)
- simple configuration (Nginx)
- no deployment related code
; run without external webserver
*** Apache version
Apache/1.3.42 (Unix) mod_perl/1.31
**more than 6 years old**
*** Dancer2 Advantages
- Clean OO interface
- Routes
- Hooks
- Engines
- Multiple Applications
- Web application
- REST API
- Admin interface
*** Manual SQL vs DBIx::Class
- Manual SQL
- error prone
- compatibility problems
- less secure
- DBIx::Class
- Business logic
- works on dozens of RDBMS
- usually faster
- more secure
** More Reasons for "No act on ACT"
- Single Point of Failure
- Development
- Responsiveness
- No https://
*** Single Point of Failure
- Baltimore Perl Workshop
- Eventbrite
*** Development
- Last commit on ACT: July 2015 [[https://github.com/book/Act]]
- Last commit on ACT in the box: September 2015
*** Hackathon in Lyon
[[s-h-stefan-hornburg-racke-no-act-on-act-en-8.jpg]]
*** Responsiveness
[[s-h-stefan-hornburg-racke-no-act-on-act-en-3.jpg][Picture by Guillaume Brocker, CC BY-SA 3.0]]
** Perl Dancer Conference Website
[[s-h-stefan-hornburg-racke-no-act-on-act-en-4.png]]
[[https://github.com/interchange/Perl-Dancer-Conference]]
** Web Application Features
- Maps with Leaflet
- Cropping Photos
- Administration
- SEO / Modern Design
- Dancer2::Debugger
*** Maps with Leaflet
- Venue on Frontpage
- Leaflet library
- Leaflet code
- User map
**** Venue on Frontpage
[[s-h-stefan-hornburg-racke-no-act-on-act-en-7.png]]
**** Leaflet Library
[[http://leafletjs.com/][Leaflet Javascript library]]
**** Leaflet Code
var map = L.map('map').setView([48.20078,16.36826], 13);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'petermottram.mp1dpak2',
accessToken: 'pk.eyJ1IjoicGV0ZXJtb3R0cmFtIiwiYSI6IjE1NWI5NjRjN2IxNjNkYTM1MzI3YzY5M2E0YjZjMDc0In0.T0bpnZGXCQBSW_SOv_nWHA'
}).addTo(map);
var marker2 = L.marker([48.18246, 16.38075]).addTo(map);
marker2.bindPopup("Hotel Schani Wien
Karl-Popper-Straße 22
Conference Venue
21/22 Oct");
$("#marker2").click(function(){
marker2.openPopup();
return false;
});
**** User Map
[[s-h-stefan-hornburg-racke-no-act-on-act-en-8.png][User Map]]
*** Cropping photos
You can drag and drop or uplad your photo and crop it
in our website.
**** Current photo
[[s-h-stefan-hornburg-racke-no-act-on-act-en-9.png][/profile/photo]]
**** Ballerina
; https://pixabay.com/en/ballet-dance-ballerina-1033163/
[[s-h-stefan-hornburg-racke-no-act-on-act-en-5.jpg]]
**** Cropping I
[[s-h-stefan-hornburg-racke-no-act-on-act-en-11.png]]
**** Cropping II
[[s-h-stefan-hornburg-racke-no-act-on-act-en-14.png]]
**** Final Result
[[s-h-stefan-hornburg-racke-no-act-on-act-en-7.jpg]]
**** Jcrop Library
[[https://github.com/tapmodo/Jcrop][Jcrop - jQuery Image Cropping Plugin]]
*** SEO / Modern Web Design
- Secure site with HTTPS
- Speaking links
**** Secure site with HTTPS
- More secure and gives users more confidence
- Small ranking boost with Google
- Free certificates with [[https://letsencrypt.org/][Let's Encrypt]]
**** Speaking Links I
[[s-h-stefan-hornburg-racke-no-act-on-act-en-1.jpg][No act on ACT]]
**** Speaking Links II
ACT :: [[http://act.yapc.eu/ye2016/talk/6780]]
PDC :: [[https://www.perl.dance/talks/40-no-act-on-act]]
*** Administration
- Users
- Talks
- Tickets
- Events
- News
**** Navigation
[[s-h-stefan-hornburg-racke-no-act-on-act-en-3.png]]
*** Development
**** Dancer2::Debugger
[[https://www.perl.dance/talks/41-plack-debugger-meets-dancer2][Dancer2::Debugger Presentation]]
[[s-h-stefan-hornburg-racke-no-act-on-act-en-17.png]]
** DBIx::Class Techniques
- Set Based DBIx::Class [[http://www.perladvent.org/2012/2012-12-21.html]]
- Truth of ResultSet
- Chaining
- Relationship traversal
- Predefined searches
- Hashref Inflation
*** Truth of ResultSet
This doesn't execute SQL:
my $talks = $schema->resultset('Talk')->search(...);
This does:
my $first_talk = $schema->resultset('Talk')
->search(...)->first;
*** Chaining
my $talks = $schema->resultset('Talk')
->search({-bool => 'accepted'})
->search({conferences_id => 1})
->search({room => { '!=' => '' }),
->search({start_time => {
'>=' => '2015-10-22 00:00:00'
'<=' => '2015-10-23 00:00:00'
}}),
);
*** Relationship Traversal
# countries dropdown
$tokens->{countries} = [
$users->search_related(
'addresses',
{
type => 'primary',
},
)->search_related(
'country', undef,
{
columns => [ 'country_iso_code', 'name' ],
distinct => 1,
order_by => 'country.name',
}
)->hri->all
];
*** Hashref Inflator
# countries dropdown
$tokens->{countries} = [
rset('Country')->search( undef,
{ columns => [ 'country_iso_code', 'name' ],
order_by => 'name' } )
->hri->all
];
unshift @{ $tokens->{countries} },
{ country_iso_code => undef, name => "Select Country" };
*** Predefined Searches
User class:
sub last_conference_attended {
my $self = shift;
my $conference = $self->conferences->search({}, {
order_by => { -desc => 'start_date' },
})->first;
}
Web application:
my $conference = $user->last_conference_attended;
; *** Convenience Methods
;
; =add_to_media=
; *** Candy, components and helpers
; - Candy
; - Hashrefinflator
; *** Deployment Handler
** Dancer2
- Code structure
- Hooks
- Plugins
- Plack::Middleware
*** Code Structure
- Main module
- Multiple modules for routes
**** Main Module
use Dancer2;
use PerlDance::Routes::Account;
use PerlDance::Routes::Admin;
use PerlDance::Routes::Data;
use PerlDance::Routes::PayPal;
use PerlDance::Routes::Profile;
use PerlDance::Routes::Survey;
use PerlDance::Routes::Talk;
use PerlDance::Routes::User;
use PerlDance::Routes::Wiki;
**** Route module I
use Dancer2 appname => 'PerlDance';
use Dancer2::Plugin::Auth::Extensible;
use Dancer2::Plugin::DataTransposeValidator;
use Dancer2::Plugin::DBIC;
use Dancer2::Plugin::Email;
use Dancer2::Plugin::Deferred;
use Dancer2::Plugin::Interchange6;
use Dancer2::Plugin::TemplateFlute;
prefix '/profile';
**** Route module II
get '/talk/create' => sub {
my $tokens = {
title => "New Talk",
};
$tokens->{form} = form('create-update-talk');
$tokens->{form}->reset;
$tokens->{form}->fill( duration => 40 );
add_durations_token($tokens);
template 'profile/create_update_talk', $tokens;
};
*** Hooks used
; A classic example
hook 'before_template_render' => sub {
my $tokens = shift;
if ( my $user = logged_in_user ) {
$tokens->{logged_in_user} = schema->current_user;
}
$tokens->{conference_name} = setting('conference_name');
};
*** Plugins used
Dancer2::Plugin::Auth::Extensible :: User Authentication
Dancer2::Plugin::DataTransposeValidator :: Form validation
Dancer2::Plugin::DBIC :: DBIx::Class Wrapper
Dancer2::Plugin::Deferred :: Flash messages after redirect
Dancer2::Plugin::Email :: Sending emails
Dancer2::Plugin::Interchange6 :: Cart and other business functions
Dancer2::Plugin::TemplateFlute :: Form handling
*** Plack Middleware
[[s-h-stefan-hornburg-racke-no-act-on-act-en-5.png]]
[[http://blogs.perl.org/users/jakob/2012/09/the-joy-of-psgi-middleware.html][Joy of PSGI middleware]]
**** Cross-site request forgery (CSRF/XSRF)
[[https://metacpan.org/pod/Plack::Middleware::XSRFBlock][Plack::Middleware::XSRFBlock]]
# bin/app.psgi
use Plack::Builder;
use PerlDance;
my $app = PerlDance->to_app;
builder {
enable 'Session';
enable 'XSRFBlock',
cookie_name => 'PerlDance-XSRF-Token',
meta_tag => 'xsrf-meta',
cookie_options => { httponly => 1, };
enable 'XForwardedFor',
trust => [qw( 127.0.0.1 10.0.0.0/8 172.16.0.0/20 192.168.0.0/16 )];
$app;
}
** Summary
- Modern Perl
- Missing features
- Perl Dancer Conference 2016
- Call for developers
- Ask questions
*** Modern Perl
*** Missing features
- Multilingual [[https://github.com/interchange/Perl-Dancer-Conference/issues/8][GH #8]]
- Drag and drop schedule tool
- Multisite
- Multiple speakers [[https://github.com/interchange/Perl-Dancer-Conference/issues/104][GH #104]]
*** Perl Dancer Conference 2016
[[s-h-stefan-hornburg-racke-no-act-on-act-en-4.png]]
*** Call for developers
[[https://github.com/interchange/Perl-Dancer-Conference]]
*** Questions
Questions?