X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2Fstemmaweb%2FController%2FRoot.pm;h=abc19522939b97edf1f1df04127b09158b00b292;hb=e0b902362ea75e07419933809f6cf99a2f2d082c;hp=494f5c18d8f3dec4fad44764de46f2cbed5828c2;hpb=75354c3abbba7d3146b2c676009d8b614ab8699a;p=scpubgit%2Fstemmaweb.git diff --git a/lib/stemmaweb/Controller/Root.pm b/lib/stemmaweb/Controller/Root.pm index 494f5c1..abc1952 100644 --- a/lib/stemmaweb/Controller/Root.pm +++ b/lib/stemmaweb/Controller/Root.pm @@ -1,4 +1,5 @@ package stemmaweb::Controller::Root; +use File::Temp; use Moose; use namespace::autoclean; use Text::Tradition::Analysis qw/ run_analysis /; @@ -33,9 +34,24 @@ components will be loaded. sub index :Path :Args(0) { my ( $self, $c ) = @_; + # Are we being asked to load a text immediately? If so + if( $c->req->param('withtradition') ) { + $c->stash->{'withtradition'} = $c->req->param('withtradition'); + } $c->stash->{template} = 'index.tt'; } +=head2 about + +A general overview/documentation page for the site. + +=cut + +sub about :Local :Args(0) { + my( $self, $c ) = @_; + $c->stash->{template} = 'about.tt'; +} + =head1 Elements of index page =head2 directory @@ -74,7 +90,8 @@ sub directory :Local :Args(0) { { name: , language: , public: , - file: } + filename: , + file: } Creates a new tradition belonging to the logged-in user, with the given name and the collation given in the uploaded file. The file type is indicated via @@ -83,6 +100,7 @@ name of the new tradition. =cut +## TODO Figure out how to mimic old-style HTML file uploads in AJAX / HTML5 sub newtradition :Local :Args(0) { my( $self, $c ) = @_; return _json_error( $c, 403, 'Cannot save a tradition without being logged in' ) @@ -91,16 +109,18 @@ sub newtradition :Local :Args(0) { my $user = $c->user->get_object; # Grab the file upload, check its name/extension, and call the # appropriate parser(s). - my $upload = $c->request->upload('file'); + my $upload = File::Temp->new(); + print $upload $c->request->param('file'); + close $upload; my $name = $c->request->param('name') || 'Uploaded tradition'; my $lang = $c->request->param( 'language' ) || 'Default'; my $public = $c->request->param( 'public' ) ? 1 : undef; - my( $ext ) = $upload->filename =~ /\.(\w+)$/; + my( $ext ) = $c->request->param( 'filename' ) =~ /\.(\w+)$/; my %newopts = ( 'name' => $name, 'language' => $lang, 'public' => $public, - 'file' => $upload->tempname + 'file' => $upload->filename ); my $tradition; @@ -115,7 +135,10 @@ sub newtradition :Local :Args(0) { } catch { $errmsg = "Unexpected parsing error"; } - last if $tradition; + if( $tradition ) { + $errmsg = undef; + last; + } } } elsif( $ext =~ /^(txt|csv|xls(x)?)$/ ) { # If it's Excel we need to pass excel => $ext; @@ -137,7 +160,7 @@ sub newtradition :Local :Args(0) { } } else { # Error unless we have a recognized filename extension - return _json_error( $c, 500, "Unrecognized file type extension $ext" ); + return _json_error( $c, 403, "Unrecognized file type extension $ext" ); } # Save the tradition if we have it, and return its data or else the @@ -173,7 +196,7 @@ sub textinfo :Local :Args(1) { my( $self, $c, $textid ) = @_; my $tradition = $c->model('Directory')->tradition( $textid ); unless( $tradition ) { - return _json_error( $c, 500, "No tradition with ID $textid" ); + return _json_error( $c, 404, "No tradition with ID $textid" ); } my $ok = _check_permission( $c, $tradition ); return unless $ok; @@ -185,37 +208,53 @@ sub textinfo :Local :Args(1) { # Handle changes to owner-accessible parameters my $m = $c->model('Directory'); my $changed; - # Handle scalar params - foreach my $param ( qw/ name language / ) { - if( exists $params->{$param} ) { - my $newval = delete $params->{$param}; - unless( $tradition->$param eq $newval ) { - try { - $tradition->$param( $newval ); - } catch { - return _json_error( $c, 500, "Error setting $param to $newval" ); - } + # Handle name param - easy + if( exists $params->{name} ) { + my $newname = delete $params->{name}; + unless( $tradition->name eq $newname ) { + try { + $tradition->name( $newname ); $changed = 1; + } catch { + return _json_error( $c, 500, "Error setting name to $newname" ); } } } + # Handle language param, making Default => null + my $langval = delete $params->{language} || 'Default'; + unless( $tradition->language eq $langval ) { + try { + $tradition->language( $langval ); + $changed = 1; + } catch { + return _json_error( $c, 500, "Error setting language to $langval" ); + } + } + # Handle our boolean + my $ispublic = $tradition->public; if( delete $params->{'public'} ) { # if it's any true value... $tradition->public( 1 ); + $changed = 1 unless $ispublic; + } else { # the checkbox was unchecked, ergo it should not be public + $tradition->public( 0 ); + $changed = 1 if $ispublic; } - # Handle ownership changes + + # Handle ownership change my $newuser; if( exists $params->{'owner'} ) { # Only admins can update user / owner my $newownerid = delete $params->{'owner'}; - unless( $tradition->has_user && $tradition->user->id eq $newownerid ) { + unless( !$newownerid || + ( $tradition->has_user && $tradition->user->id eq $newownerid ) ) { unless( $c->user->get_object->is_admin ) { return _json_error( $c, 403, "Only admin users can change tradition ownership" ); } - $newuser = $m->lookup_user( $params->{'owner'} ); + $newuser = $m->find_user({ username => $newownerid }); unless( $newuser ) { - return _json_error( $c, 500, "No such user " . $params->{'owner'} ); + return _json_error( $c, 500, "No such user " . $newownerid ); } $newuser->add_tradition( $tradition ); $changed = 1; @@ -236,11 +275,11 @@ sub textinfo :Local :Args(1) { textid => $textid, name => $tradition->name, language => $tradition->language, - public => $tradition->public, + public => $tradition->public || 0, owner => $tradition->user ? $tradition->user->id : undef, witnesses => [ map { $_->sigil } $tradition->witnesses ], }; - my @stemmasvg = map { $_->as_svg({ size => [ 500, 375 ] }) } $tradition->stemmata; + my @stemmasvg = map { $_->as_svg() } $tradition->stemmata; map { $_ =~ s/\n/ /mg } @stemmasvg; $textinfo->{stemmata} = \@stemmasvg; $c->stash->{'result'} = $textinfo; @@ -259,7 +298,7 @@ sub variantgraph :Local :Args(1) { my( $self, $c, $textid ) = @_; my $tradition = $c->model('Directory')->tradition( $textid ); unless( $tradition ) { - return _json_error( $c, 500, "No tradition with ID $textid" ); + return _json_error( $c, 404, "No tradition with ID $textid" ); } my $ok = _check_permission( $c, $tradition ); return unless $ok; @@ -286,7 +325,7 @@ sub stemma :Local :Args(2) { my $m = $c->model('Directory'); my $tradition = $m->tradition( $textid ); unless( $tradition ) { - return _json_error( $c, 500, "No tradition with ID $textid" ); + return _json_error( $c, 404, "No tradition with ID $textid" ); } my $ok = _check_permission( $c, $tradition ); return unless $ok; @@ -299,14 +338,17 @@ sub stemma :Local :Args(2) { try { if( $stemmaid eq 'n' ) { # We are adding a new stemma. + $stemmaid = $tradition->stemma_count; $stemma = $tradition->add_stemma( 'dot' => $dot ); + } elsif( $stemmaid !~ /^\d+$/ ) { + return _json_error( $c, 403, "Invalid stemma ID specification $stemmaid" ); } elsif( $stemmaid < $tradition->stemma_count ) { # We are updating an existing stemma. $stemma = $tradition->stemma( $stemmaid ); $stemma->alter_graph( $dot ); } else { # Unrecognized stemma ID - return _json_error( $c, 500, "No stemma at index $stemmaid, cannot update" ); + return _json_error( $c, 404, "No stemma at index $stemmaid, cannot update" ); } } catch ( Text::Tradition::Error $e ) { return _json_error( $c, 500, $e->message ); @@ -321,13 +363,32 @@ sub stemma :Local :Args(2) { # For a GET or a successful POST request, return the SVG representation # of the stemma in question, if any. - $c->log->debug( "Received Accept header: " . $c->req->header('Accept') ); if( !$stemma && $tradition->stemma_count > $stemmaid ) { $stemma = $tradition->stemma( $stemmaid ); } - $c->stash->{'result'} = $stemma - ? $stemma->as_svg( { size => [ 500, 375 ] } ) : ''; - $c->forward('View::SVG'); + my $stemma_xml = $stemma ? $stemma->as_svg() : ''; + # What was requested, XML or JSON? + my $return_view = 'SVG'; + if( my $accept_header = $c->req->header('Accept') ) { + $c->log->debug( "Received Accept header: $accept_header" ); + foreach my $type ( split( /,\s*/, $accept_header ) ) { + # If we were first asked for XML, return SVG + last if $type =~ /^(application|text)\/xml$/; + # If we were first asked for JSON, return JSON + if( $type eq 'application/json' ) { + $return_view = 'JSON'; + last; + } + } + } + if( $return_view eq 'SVG' ) { + $c->stash->{'result'} = $stemma_xml; + $c->forward('View::SVG'); + } else { # JSON + $stemma_xml =~ s/\n/ /mg; + $c->stash->{'result'} = { 'stemmaid' => $stemmaid, 'stemmasvg' => $stemma_xml }; + $c->forward('View::JSON'); + } } =head2 stemmadot @@ -343,13 +404,13 @@ sub stemmadot :Local :Args(2) { my $m = $c->model('Directory'); my $tradition = $m->tradition( $textid ); unless( $tradition ) { - return _json_error( $c, 500, "No tradition with ID $textid" ); + return _json_error( $c, 404, "No tradition with ID $textid" ); } my $ok = _check_permission( $c, $tradition ); return unless $ok; my $stemma = $tradition->stemma( $stemmaid ); unless( $stemma ) { - return _json_error( $c, 500, "Tradition $textid has no stemma ID $stemmaid" ); + return _json_error( $c, 404, "Tradition $textid has no stemma ID $stemmaid" ); } # Get the dot and transmute its line breaks to literal '|n' $c->stash->{'result'} = { 'dot' => $stemma->editable( { linesep => '|n' } ) };