#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?