Bag Of Tricks From Iusethis

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    4 Favorites & 2 Groups

    Bag Of Tricks From Iusethis - Presentation Transcript

    1. Bag of tricks from iusethis.com
    2. 6. Who's behind iusethis? Is it a corporate thingie? Nah. Iusethis was made by Arne and Marcus. We're just these guys, you know? But we really know where our towels are.
    3. Social Software For Software
    4. Status after 1 year • 15.000 registered users • 4.000 registered apps • ~ 250.000 page views per day • 20.000 revisions committed to SVN
    5. Catalyst made such rapid development possible
    6. While still keeping it sane to maintain
    7. Design Philosophies
    8. Design Philosophies • URLs matter!
    9. Design Philosophies • URLs matter! • AJAX when it makes sense
    10. Design Philosophies • URLs matter! • AJAX when it makes sense • Support standards
    11. Design Philosophies • URLs matter! • AJAX when it makes sense • Support standards • Provide alternative data-formats
    12. Design Philosophies • URLs matter! • AJAX when it makes sense • Support standards • Provide alternative data-formats • The user owns his data
    13. AJAX
    14. AJAH
    15. AJAH XMLHTTPRequest and DIV filling
    16. Enhance Not Replace
    17. Example: <span><a href=\"\" onclick= \"CallBmk(); return false;\" >Bookmark this</a></span>
    18. NO!
    19. Lynx Friendly First: <a href=”/do_some_shit” id=”do_some_shit”/>
    20. Meanwhile... <script type=”text/javascript”> $(‘do_some_shit’).onclick=function() { // Fill that div good! return false; }// /do_some_shit is never called </script>
    21. Side note: <a href=”/do_some_shit” id=”do_some_shit”/> <a href=”[%c.uri_for(‘/ do_some_shit’)%]” id=”do_some_shit”/>
    22. Ditto for Forms <form action=”[%c.uri_for(‘/doit’)%]” id=”doit”/> <script type=”text/javascript”> $(‘doit’).onsubmit=function() { // Do something neat with the form return false; } // form is never submitted </script>
    23. Server side Validation without submit
    24. <script type=”text/javascript”> $(‘register_screenname’).onchange = function() { var screenname=”name=”+ $(‘register_screenname’).value var updater=new Ajax.Updater( ‘register_screenname_errors’, ‘[%c.uri_for(‘/jsrpc/ user_name_available’)%]’, {parameters: screenname }); } </script> iusethis forms are generated by HTML::Widget - lots of hooks through classes/ids
    25. And in the Controller:
    26. sub user_name_available : Local { my ($self,$c) = @_; if ($c->model('DB::Person') ->search({ screenname => $c->req->param('name') })->count()) { $c->res->body('<span>'. $c->req->param('name'). ' is already registered</span>'); } else { $c->res->body(' '); } }
    27. Case Study: iusethis counter
    28. <div class=”iusethis”> <div id=”iuse_[%app.short%]” class=”count”> [%app.count%]</div> <a id=”mark_[%app.id%]” href=\"[%c.uri_for ('/app/iusethis', app.id,secret,c.user.obj.screenname)%]\" title=\"Mark as used\">i use this</a></div> <script type=”text/javascript”> $(‘mark_[%app.id%]’).onclick=function() { new Ajax.Updater('iuse_[%app.short%]', '[%c.uri_for('/app/iusethis', app.id,secret,c.user.obj.screenname)%]', {evalScripts:true,method:'post', postBody:'count=[%use_count%]'}); return false; } </script>
    29. Inline Javascript
    30. Behaviour.js Cleaner - But slower
    31. Meanwhile, in the controller...
    32. sub iusethis : Local { my ($self,$c,$id,$secret,$screenname) = @_; my $app:Stashed = $c->model('DB::Application') ->find($id); $c->stash->{app}->add_to_iuses( {person=>$c->user_object}); $c->forward('app',[$app->short]) unless( $c->req->header('x-requested-with') && $c->req->header('x-requested-with') eq 'XMLHttpRequest'); # otherwise render ajax template }
    33. $secret ? Protect against abuse Catalyst::Plugin::RequestToken
    34. Let’s look at a variant
    35. Email Validation sub confirm_email : Private { my ($self,$c,$user) = @_; my $item:Stashed=$user; my $seed:Stashed= md5_hex( $user->registered.$c->config->{seed}); $c->email( header => [ From => $c->config->{system_mail}, To => $user->email, Subject => 'iusethis email confirmation.' ], body => $c->view('TT')->render ($c,'mailwelcome.tt'), ); my $template:Stashed='validate.tt';
    36. RSS
    37. sub hot_xml : Path('/hot.rss') { my ($self,$c) = @_; my $feed:Stashed; $c->forward('hot'); $c->forward('rss'); $feed->title( 'Hot apps from iusethis.com'); $feed->link( $c->uri_for('/hot')); $c->res->body($feed->as_xml); }
    38. sub rss : Private { my ($self,$c) = @_; my $feed:Stashed= XML::Feed->new('RSS'); $feed->link($c->uri_for('/')); $feed->tagline( 'i use this. What do you use?'); my $app:Stashed; if ($apps) { while( my $app = $apps->next ) { .... # New entry } } }
    39. Another alternative rss.tt: <?xml version=\"1.0\" encoding=\"UTF-8\"?> <rss version=\"2.0\" xmlns:iusethis=\"http://osx.iusethis.com/ ns/rss\" xmlns:dc=\"http://purl.org/dc/ elements/1.1/\"> <channel> <title>[% title || 'RSS Feed from iusethis.com '%]</title> .....
    40. Autodiscovery header.tt: [% IF rss %] <link rel=\"alternate\" title=\"Iusethis RSS\" href=\"[%rss%]\" type=\"application/rss+xml\"/> [% END %]
    41. Authentication
    42. DBIC Auth Plugins: Authentication Authentication::Store::DBIC Authentication::Credential::Password config: authentication: dbic: user_class: DBIC::Person password_field: password user_field: - screenname - email
    43. And in the Controller:
    44. if ($c->req->param('email')) { if ( $c->login($c->req->param('email'),$c->req->param ('pass')) ) { my $root=$c->uri_for('/'); delete $c->req->params->{referer} if $c->req->params->{referer} eq $root || $c->req->params->{referer} !~ m/^$root/ || $c->req->params->{referer} eq $root.\"logout\"; $c->res->redirect( $c->req->params->{referer} || $c->uri_for('/user',$c->user->obj->screenname)); if ($c->req->param('openid')) { $c->user->obj->openid($c->req->param('openid')); $c->user->obj->update(); } } else { my $alert:Stashed='Login failed'; }
    45. Basic Auth Plugins: Authentication::Credential::HTTP config: authentication: http: type: basic
    46. And in the Controller:
    47. sub auto : Private { my ( $self, $c ) = @_; return 1 if $c->action eq 'api/index'; $c->authorization_required( realm => \"iusethis\" ); unless ($c->req->method eq 'POST') { $c->res->body('API Requests require HTTP POST'); return 0; } return 1; }
    48. OpenID Plugins: Authentication::Credential::OpenID
    49. And in the Controller:
    50. if ($c->authenticate_openid) { if (my $person=$c->model('DBIC::Person') ->find({openid=>$c->user->url})) { my $user=$c->get_user($person->screenname) || die \"Could not make user object for \" . $person->screenname.\"\\n\"; $c->set_authenticated($user); return $c->res->redirect( $c->uri_for('/user',$person->screenname)); } my $openid:Stashed=$c->user->url; $c->logout; } elsif (! @{$c->error}) { return if $c->res->redirect; $c->res->redirect($c->uri_for( '/login',{openid_failed=>1})); } };
    51. OPML Outline Processor Markup Language -- is an XML format for outlines.
    52. sub user_opml : Global { my ($self,$c,$screenname)= @_; my $user=$c->model('DBIC::Person') ->search({ screenname=>$screenname})->first; my $opml=XML::OPML::SimpleGen->new(); $opml->head(title =>'Apps used by '.$user->screenname); my $apps=$user->applications; ...
    53. while (my $app=$apps->next) { $opml->add_outline( text => $app->name, count => $app->iuses->count, icon => $app->has_icon($c) ? $app->icon_uri($c) : $c->uri_for_img('default.png') ->as_string, xmlUrl => $c->uri_for('/appcast',$app->short) ->as_string, group => $app->uses_this($user) ->iloveit ? 'loved' : 'apps', ); } $c->res->body($opml->as_string); $c->res->content_type('text/xml'); }
    54. Tags
    55. CREATE TABLE tag ( id INTEGER PRIMARY KEY, name TEXT, application INT REFERENCES application );
    56. Aggregating popular tags
    57. sub aggregated : ResultSet { return scalar shift->search({'me.name', { -not_in => [ @banned_tags ]}}, { select=>[{count => 'id'},'name' ], as=>[qw/tagcount name/], group_by=>[qw/name/], order_by=>\"count(id) DESC\", page=>1, rows=>(shift||10) }); }
    58. Finding related tags
    59. sub related : ResultSet { my ($self,$tag)=@_; return $self->search({ 'related.name'=>$tag, 'me.name',{-not_in => [@banned_tags ]}, 'me.name'=>(ref $tag ? {-not_in,$tag} : {'!=',$tag}), },{ select=>[{count => 'me.name'},'me.name' ], as=>[qw/tagcount name/], join=>'related', group_by=>[qw/me.name/], order_by=>\"count(me.name) DESC\", page=>1,rows=>10, }); }
    60. Tag Cloud
    61. HTML::TagCloud
    62. 0.33 Mon Mar 13 20:26:36 GMT 2006 - add a 'tags' method that extracts most of the logic from the html method. It also adds support for setting levels as a parameter to the constructor. It defaults to the before-hardcoded 24. (thanks to Marcus Ramberg) ---- <marcus> acme++
    63. sub get_cloud :ResultSet { my ($self,$c,$limit) = @_; my $cloud = HTML::TagCloud->new(levels=>5); my $tags = $self->aggregated($limit||75); while( my $tag=$tags->next() ) { $cloud->add(lc($tag->name),$c->uri_for('/ tag', lc($tag->name)),$tag->get_column ('tagcount')); } return $cloud; }
    64. Caching
    65. Catalyst::Plugin::PageCache
    66. page_cache: auto_check_user: 1 set_http_headers: 1 expires: 120 no_cache_debug: 1 auto_cache: - '/top*' - '/hot*'
    67. Only for Anon
    68. Not POST
    69. Just Works
    70. Profile Builder
    71. OSX perl app
    72. Just core modules
    73. @apps= map { make_short($_) } grep{ /\\.(?:app|wdgt|prefPane)$/ } find_apps('/Applications'), find_apps($ENV{HOME}.\"/Library/ PreferencePanes\"), find_apps($ENV{HOME}.\"/Library/Widgets\"); my $data='-F apps='.join(' -F apps=',@apps); my $res=`curl -s $data http:// osx.iusethis.com/profile/send`; system('open','http://osx.iusethis.com/ profile/view/'.$res.'?match=1');
    74. Last Trick
    75. iwatchthis .com
    76. Random Profile
    77. sub random : Global { my ($self,$c) = @_; my $user=$c->model('DB::Person') ->search({},{ rows => 1, order_by => \"rand()\", })->next(); $c->res->redirect( $c->uri_for('/'.$user->login)); }
    78. Another person
    79. sub random : Global { my ($self,$c,$feed) = @_; my $user=$c->model('DB::Person') ->search({ login => {\"-not_in\"=>[$feed]}, },{ rows => 1, order_by => \"rand()\", })->next(); $c->res->redirect( $c->uri_for('/'.$user->login)); }
    80. one with movies
    81. sub random : Global { my ($self,$c,$feed) = @_; my $user=$c->model('DB::Person') ->search({ login => { '!=' => $feed}, },{ rows => 1, order_by => \"rand()\", join => [qw/items/], having=>{'count(items.id)' => {'>',0 }}, group_by => 'me.id'})->next(); $c->res->redirect( $c->uri_for('/'.$user->login)); }
    82. not my profile
    83. sub random : Global { my ($self,$c,$feed) = @_; my $user=$c->model('DB::Person') ->search({ login => {\"-not_in\"=>[ ($c->user_exists() ? ($feed,$c->user->obj->login) : $feed ]; },{ rows => 1, order_by => \"rand()\", join => [qw/items/], having=>{'count(items.id)' => {'>',0 }}, group_by => 'me.id'})->next(); $c->res->redirect( $c->uri_for('/'.$user->login)); }
    84. DBIx::Class It grows with you
    85. Questions? marcus@iusethis.com

    + marcusrambergmarcusramberg, 3 years ago

    custom

    2799 views, 4 favs, 7 embeds more stats

    practical examples of how I used Catalyst and DBIx: more

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 2799
      • 2486 on SlideShare
      • 313 from embeds
    • Comments 0
    • Favorites 4
    • Downloads 71
    Most viewed embeds
    • 289 views on http://blog.iusethis.com
    • 15 views on http://www.nordaaker.com
    • 4 views on http://thomas-fahle.blogspot.com
    • 2 views on http://nordaaker.com
    • 1 views on http://iwatchthis.com

    more

    All embeds
    • 289 views on http://blog.iusethis.com
    • 15 views on http://www.nordaaker.com
    • 4 views on http://thomas-fahle.blogspot.com
    • 2 views on http://nordaaker.com
    • 1 views on http://iwatchthis.com
    • 1 views on http://209.85.173.104
    • 1 views on http://192.168.10.100

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories

    Groups / Events