diff options
author | Yorhel <git@yorhel.nl> | 2015-10-03 11:53:21 +0200 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2015-10-03 11:53:21 +0200 |
commit | 728c41ccab0463bbc70817d3baa8575d4006db70 (patch) | |
tree | 295df5376ebd8e655e913d49796365e85765d44f | |
parent | f81d7164cffa5067b25b941f1ab6498a8eb5bfb0 (diff) |
formValidate: Add json_(maxitems|unique|sort) options to json template
Adds slightly more strict validation and simplifies further processing.
-rw-r--r-- | lib/VNDB/Handler/Staff.pm | 8 | ||||
-rw-r--r-- | lib/VNDB/Handler/VNEdit.pm | 43 | ||||
-rwxr-xr-x | util/vndb.pl | 48 |
3 files changed, 59 insertions, 40 deletions
diff --git a/lib/VNDB/Handler/Staff.pm b/lib/VNDB/Handler/Staff.pm index 58cd6299..88e6d7c8 100644 --- a/lib/VNDB/Handler/Staff.pm +++ b/lib/VNDB/Handler/Staff.pm @@ -191,7 +191,7 @@ sub edit { primary => $s->{aid}, aliases => [ map +{ aid => $_->{id}, name => $_->{name}, orig => $_->{original} }, - sort { $a->{name} cmp $b->{name} } @{$s->{aliases}} + sort { $a->{name} cmp $b->{name} || $a->{original} cmp $b->{original} } @{$s->{aliases}} ], ); my $frm; @@ -209,7 +209,7 @@ sub edit { { post => 'l_site', required => 0, template => 'weburl', maxlength => 250, default => '' }, { post => 'l_twitter', required => 0, maxlength => 16, default => '', regex => [ qr/^\S+$/, mt('_staffe_form_tw_err') ] }, { post => 'l_anidb', required => 0, template => 'id', default => undef }, - { post => 'aliases', template => 'json', json_fields => [ + { post => 'aliases', template => 'json', json_sort => ['name','orig'], json_fields => [ { field => 'name', required => 1, maxlength => 200 }, { field => 'orig', required => 0, maxlength => 200, default => '' }, { field => 'aid', required => 0, template => 'id', default => 0 }, @@ -220,14 +220,12 @@ sub edit { ); if(!$frm->{_err}) { - my $aliases = [ sort { $a->{name} cmp $b->{name} } @{$frm->{aliases}} ]; my %old_aliases = $sid ? ( map +($_->{id} => 1), @{$self->dbStaffAliasIds($sid)} ) : (); $frm->{primary} = 0 unless exists $old_aliases{$frm->{primary}}; # reset aid to zero for newly added aliases. - $_->{aid} *= $old_aliases{$_->{aid}} ? 1 : 0 for (sort { $a->{name} cmp $b->{name} } @$aliases); + $_->{aid} *= $old_aliases{$_->{aid}} ? 1 : 0 for(@{$frm->{aliases}}); - $frm->{aliases} = $aliases; $frm->{ihid} = $frm->{ihid} ?1:0; $frm->{ilock} = $frm->{ilock}?1:0; $frm->{aid} = $frm->{primary} if $sid; diff --git a/lib/VNDB/Handler/VNEdit.pm b/lib/VNDB/Handler/VNEdit.pm index 6827557d..8869d1a9 100644 --- a/lib/VNDB/Handler/VNEdit.pm +++ b/lib/VNDB/Handler/VNEdit.pm @@ -120,18 +120,18 @@ sub edit { { post => 'anime', required => 0, default => '' }, { post => 'image', required => 0, default => 0, template => 'id' }, { post => 'img_nsfw', required => 0, default => 0 }, - { post => 'credits', required => 0, template => 'json', json_fields => [ + { post => 'credits', required => 0, template => 'json', json_unique => ['aid','role'], json_sort => ['aid','role'], json_fields => [ { field => 'aid', required => 1, template => 'id' }, { field => 'role', required => 1, enum => $self->{staff_roles} }, { field => 'note', required => 0, maxlength => 250, default => '' }, ]}, - { post => 'seiyuu', required => 0, template => 'json', json_fields => [ + { post => 'seiyuu', required => 0, template => 'json', json_unique => ['aid','cid'], json_sort => ['aid','cid'], json_fields => [ { field => 'aid', required => 1, template => 'id' }, { field => 'cid', required => 1, template => 'id' }, { field => 'note', required => 0, maxlength => 250, default => '' }, ]}, { post => 'vnrelations', required => 0, default => '', maxlength => 5000 }, - { post => 'screenshots', required => 0, template => 'json', json_fields => [ + { post => 'screenshots', required => 0, template => 'json', json_maxitems => 10, json_unique => 'id', json_sort => 'id', json_fields => [ { field => 'id', required => 1, template => 'id' }, { field => 'rid', required => 1, template => 'id' }, { field => 'nsfw', required => 1, template => 'uint', enum => [0,1] }, @@ -143,34 +143,6 @@ sub edit { # handle image upload $frm->{image} = _uploadimage($self, $frm) if !$nosubmit; - my (@credits, @seiyuu); - if(!$nosubmit && !$frm->{_err}) { - # ensure submitted alias IDs exist within database - my @alist = map $_->{aid}, @{$frm->{credits}}, @{$frm->{seiyuu}}; - my %staff = @alist ? map +($_->{aid}, 1), @{$self->dbStaffGet(aid => \@alist, results => 200)} : (); - - # check for duplicate credits - my $last_c = { aid => 0, role => '' }; - for my $c (sort { $a->{aid} <=> $b->{aid} || $a->{role} cmp $b->{role} } @{$frm->{credits}}) { - next unless exists $staff{0+$c->{aid}}; - # discard entries with identical name & role - next if $last_c->{aid} == $c->{aid} && $last_c->{role} eq $c->{role}; - push @credits, $c; - $last_c = $c; - } - - # if character list is empty, any seiyuu data will be discarded - if (@$chars && @{$frm->{seiyuu}}) { - my %vn_chars = map +($_->{id} => 1), @$chars; - my $last_s = { aid => 0, cid => 0 }; - for my $s (sort { $a->{aid} <=> $b->{aid} || $a->{cid} <=> $b->{cid} } @{$frm->{seiyuu}}) { - next unless $staff{0+$s->{aid}} && $vn_chars{0+$s->{cid}}; # weed out odd credits - next if $last_s->{aid} == $s->{aid} && $last_s->{cid} == $s->{cid}; - push @seiyuu, $s; - $last_s = $s; - } - } - } if(!$nosubmit && !$frm->{_err}) { # normalize aliases $frm->{alias} = join "\n", map { s/^ +//g; s/ +$//g; $_?($_):() } split /\n/, $frm->{alias}; @@ -184,6 +156,13 @@ sub edit { my $anime = { map +($_=>1), grep /^[0-9]+$/, split /[ ,]+/, $frm->{anime} }; my $relations = [ map { /^([a-z]+),([0-9]+),([01]),(.+)$/ && (!$vid || $2 != $vid) ? [ $1, $2, $3, $4 ] : () } split /\|\|\|/, $frm->{vnrelations} ]; + # Ensure submitted alias / character IDs exist within database + my @alist = map $_->{aid}, @{$frm->{credits}}, @{$frm->{seiyuu}}; + my %staff = @alist ? map +($_->{aid}, 1), @{$self->dbStaffGet(aid => \@alist, results => 200)} : (); + my %vn_chars = map +($_->{id} => 1), @$chars; + $frm->{credits} = [ grep $staff{$_->{aid}}, @{$frm->{credits}} ]; + $frm->{seiyuu} = [ grep $staff{$_->{aid}} && $vn_chars{$_->{cid}}, @$chars ? @{$frm->{seiyuu}} : () ]; + $frm->{ihid} = $frm->{ihid}?1:0; $frm->{ilock} = $frm->{ilock}?1:0; $frm->{desc} = $self->bbSubstLinks($frm->{desc}); @@ -192,8 +171,6 @@ sub edit { $frm->{vnrelations} = join '|||', map $_->[0].','.$_->[1].','.($_->[2]?1:0).','.$_->[3], sort { $a->[1] <=> $b->[1]} @{$relations}; $frm->{img_nsfw} = $frm->{img_nsfw} ? 1 : 0; $frm->{screenshots} = [ sort { $a->{id} <=> $b->{id} } @{$frm->{screenshots}} ]; - $frm->{credits} = \@credits; - $frm->{seiyuu} = \@seiyuu; # nothing changed? just redirect return $self->resRedirect("/v$vid", 'post') if $vid && !form_compare(\%b4, $frm); diff --git a/util/vndb.pl b/util/vndb.pl index 3ca6604f..99f15367 100755 --- a/util/vndb.pl +++ b/util/vndb.pl @@ -17,7 +17,7 @@ use lib $ROOT.'/lib'; use TUWF ':html', 'kv_validate'; use VNDB::L10N; -use VNDB::Func 'json_encode', 'json_decode'; +use VNDB::Func 'json_decode'; use VNDBUtil 'gtintype'; use SkinFile; @@ -55,7 +55,7 @@ TUWF::set( uname => { regex => qr/^[a-z0-9-]*$/, minlength => 2, maxlength => 15 }, gtin => { func => \>intype }, editsum => { maxlength => 5000, minlength => 2 }, - json => { func => \&json_validate, inherit => ['json_fields'], default => [] }, + json => { func => \&json_validate, inherit => ['json_fields','json_maxitems','json_unique','json_sort'], default => [] }, }, ); TUWF::load_recursive('VNDB::Util', 'VNDB::DB', 'VNDB::Handler'); @@ -134,22 +134,66 @@ sub logformat { } +# Figure out if a field is treated as a number in kv_validate(). +sub json_validate_is_num { + my $opts = shift; + return 0 if !$opts->{template}; + return 1 if $opts->{template} eq 'num' || $opts->{template} eq 'int' || $opts->{template} eq 'uint'; + my $t = TUWF::set('validate_templates')->{$opts->{template}}; + return $t && json_validate_is_num($t); +} + + +sub json_validate_sort { + my($sort, $fields, $data) = @_; + + # Figure out which fields need to use number comparison + my %nums; + for my $k (@$sort) { + my $f = (grep $_->{field} eq $k, @$fields)[0]; + $nums{$k}++ if json_validate_is_num($f); + } + + # Sort + return [sort { + for(@$sort) { + my $r = $nums{$_} ? $a->{$_} <=> $b->{$_} : $a->{$_} cmp $b->{$_}; + return $r if $r; + } + 0 + } @$data]; +} + # Special validation function for simple JSON structures as form fields. It can # only validate arrays of key-value objects. The key-value objects are then # validated using kv_validate. +# TODO: json_unique implies json_sort on the same fields? These options tend to be the same. sub json_validate { my($val, $opts) = @_; my $fields = $opts->{json_fields}; + my $maxitems = $opts->{json_maxitems}; + my $unique = $opts->{json_unique}; + my $sort = $opts->{json_sort}; + $unique = [$unique] if $unique && !ref $unique; + $sort = [$sort] if $sort && !ref $sort; + my $data = eval { json_decode $val }; $_[0] = $@ ? [] : $data; return 0 if $@ || ref $data ne 'ARRAY'; + return 0 if defined($maxitems) && @$data > $maxitems; + my %known_fields = map +($_->{field},1), @$fields; + my %unique; + for my $i (0..$#$data) { return 0 if ref $data->[$i] ne 'HASH'; # Require that all keys are known and have a scalar value. return 0 if grep !$known_fields{$_} || ref($data->[$i]{$_}), keys %{$data->[$i]}; $data->[$i] = kv_validate({ field => sub { $data->[$i]{shift()} } }, $TUWF::OBJ->{_TUWF}{validate_templates}, $fields); return 0 if $data->[$i]{_err}; + return 0 if $unique && $unique{ join '|||', map $data->[$i]{$_}, @$unique }++; } + + $_[0] = json_validate_sort($sort, $fields, $data) if $sort; return 1; } |