summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2015-09-20 16:14:59 +0200
committerYorhel <git@yorhel.nl>2015-09-20 16:14:59 +0200
commited86cfd12b0bed7352e2be525b8e63cb4d6d5448 (patch)
tree321f346791cbff80c8355a736e6f4ecb90084d49
parentbb7a7cc178144457d401c3c6479a41788cf681dd (diff)
formValidate: Add json template and remove json_validate() function
This is less convenient than I had expected, because all the form handling code is designed to work with plain strings rather than any scalar. This means the json data has to be encoded again to get into $frm (not doing this means that, if the form didn't validate, the field won't be filled out correctly). And then decoded for validation, and then encoded again for comparison. I suspect the better solution is to fix the form handling code to handle arbitrary data structures: comparison can be done by deep comparison rather than a simple string compare, and the form generator can auto-encode-to-json if it sees a complex object. Another advantage of this solution is that the comparison function can be less strict with respect to number formatting. In the current scheme you have to be very careful that numbers are not automatically coerced into string format, otherwise the comparison will fail. Either way, that's an idea for the future...
-rw-r--r--data/lang.txt4
-rw-r--r--lib/VNDB/Func.pm28
-rw-r--r--lib/VNDB/Handler/Staff.pm15
-rw-r--r--lib/VNDB/Handler/VNEdit.pm31
-rwxr-xr-xutil/vndb.pl25
5 files changed, 49 insertions, 54 deletions
diff --git a/data/lang.txt b/data/lang.txt
index 281b388d..fb56f0a4 100644
--- a/data/lang.txt
+++ b/data/lang.txt
@@ -16407,12 +16407,12 @@ uk : Будь ласка, прочитайте [url,/d5.4,вказівки] пр
it : Leggi la [url,/d5.4,guida] su come usare il riepilogo modifica
:_formerr_tpl_json
-en : [_1]: Malformed staff data
+en : [_1]: Malformed data or invalid input
ru*:
cs*:
hu*:
nl*:
-de : Ungültige Stabdaten
+de*:
es*:
tr*:
uk*:
diff --git a/lib/VNDB/Func.pm b/lib/VNDB/Func.pm
index 40af8e73..02489980 100644
--- a/lib/VNDB/Func.pm
+++ b/lib/VNDB/Func.pm
@@ -11,7 +11,7 @@ use VNDBUtil;
our @EXPORT = (@VNDBUtil::EXPORT, qw|
clearfloat cssicon tagscore mt minage fil_parse fil_serialize parenttags
childtags charspoil imgpath imgurl fmtvote
- json_encode json_decode script_json json_validate
+ json_encode json_decode script_json
mtvoiced mtani mtvnlen mtrlstat mtvnlstat mtbloodt
|);
@@ -228,32 +228,6 @@ sub script_json {
}
-# 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.
-# Returns the parsed json object on success, undef on error and sets $frm->{_err}.
-# Doesn't provide a user-friendly error message if validation fails. It's the
-# responsibility of the JS code to handle the interface with the user.
-sub json_validate {
- my($frm, $name, @fields) = @_;
- my $data = eval { json_decode $frm->{$name} };
- goto error if $@ || ref $data ne 'ARRAY';
- my %known_fields = map +($_->{field},1), @fields;
- for my $i (0..$#$data) {
- goto error if ref $data->[$i] ne 'HASH';
- # Require that all keys are known and have a scalar value.
- goto error 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);
- goto error if $data->[$i]{_err};
- }
-
- return $data;
-error:
- push @{$frm->{_err}}, [ 'aliases', 'template', 'json' ] ;
- return undef;
-}
-
-
# mt() wrappers for data-dependent translation strings that have a special
# value for 'unknown'.
sub mtvoiced { !$_[0] ? mt '_unknown' : mt '_voiced_'.$_[0]; }
diff --git a/lib/VNDB/Handler/Staff.pm b/lib/VNDB/Handler/Staff.pm
index 52b2e1f1..753a1ef8 100644
--- a/lib/VNDB/Handler/Staff.pm
+++ b/lib/VNDB/Handler/Staff.pm
@@ -209,26 +209,25 @@ 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', required => 0, maxlength => 5000, default => '' },
+ { post => 'aliases', template => 'json', json_fields => [
+ { field => 'name', required => 1, maxlength => 200 },
+ { field => 'orig', required => 0, maxlength => 200, default => '' },
+ { field => 'aid', required => 0, template => 'uint', default => 0 },
+ ]},
{ post => 'editsum', template => 'editsum' },
{ post => 'ihid', required => 0 },
{ post => 'ilock', required => 0 },
);
- my $aliases = json_validate($frm, 'aliases',
- { field => 'name', required => 1, maxlength => 200 },
- { field => 'orig', required => 0, maxlength => 200, default => '' },
- { field => 'aid', required => 0, template => 'id', default => 0 },
- );
if(!$frm->{_err}) {
+ my $aliases = json_decode $frm->{aliases};
$aliases = [ sort { $a->{name} cmp $b->{name} } @$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);
- }
- if(!$frm->{_err}) {
+
$frm->{aliases} = json_encode $aliases;
$frm->{ihid} = $frm->{ihid} ?1:0;
$frm->{ilock} = $frm->{ilock}?1:0;
diff --git a/lib/VNDB/Handler/VNEdit.pm b/lib/VNDB/Handler/VNEdit.pm
index 409c80cb..1883b072 100644
--- a/lib/VNDB/Handler/VNEdit.pm
+++ b/lib/VNDB/Handler/VNEdit.pm
@@ -117,38 +117,37 @@ 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, default => '[]', maxlength => 5000 },
- { post => 'seiyuu', required => 0, default => '[]', maxlength => 5000 },
+ { post => 'credits', template => 'json', 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', template => 'json', 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, default => '', maxlength => 1000 },
{ post => 'editsum', required => !$nosubmit, template => 'editsum' },
{ post => 'ihid', required => 0 },
{ post => 'ilock', required => 0 },
);
- my $raw_c = !$frm->{_err} && json_validate($frm, 'credits',
- { field => 'aid', required => 1, template => 'id' },
- { field => 'role', required => 1, enum => $self->{staff_roles} },
- { field => 'note', required => 0, maxlength => 300, default => '' },
- );
- my $raw_s = !$frm->{_err} && json_validate($frm, 'seiyuu',
- { field => 'aid', required => 1, template => 'id' },
- { field => 'cid', required => 1, template => 'id' },
- { field => 'note', required => 0, maxlength => 300, default => '' },
- );
-
# handle image upload
$frm->{image} = _uploadimage($self, $frm) if !$nosubmit;
+ my $raw_c = !$frm->{_err} && json_decode $frm->{credits};
+ my $raw_s = !$frm->{_err} && json_decode $frm->{seiyuu};
my (@credits, @seiyuu);
if(!$nosubmit && !$frm->{_err}) {
# ensure submitted alias IDs exist within database
my @alist = map $_->{aid}, @$raw_c, @$raw_s;
- my %staff = @alist ? map +($_->{aid} => 1), @{$self->dbStaffGet(aid => \@alist, results => 200)} : ();
+ 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} } @$raw_c) {
- next unless exists $staff{$c->{aid}};
+ 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;
@@ -160,7 +159,7 @@ sub edit {
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} } @$raw_s) {
- next unless $staff{$s->{aid}} && $vn_chars{$s->{cid}}; # weed out odd credits
+ 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;
diff --git a/util/vndb.pl b/util/vndb.pl
index 9a3663a9..fd70e564 100755
--- a/util/vndb.pl
+++ b/util/vndb.pl
@@ -15,8 +15,9 @@ BEGIN { ($ROOT = abs_path $0) =~ s{/util/vndb\.pl$}{}; }
use lib $ROOT.'/lib';
-use TUWF ':html';
+use TUWF ':html', 'kv_validate';
use VNDB::L10N;
+use VNDB::Func 'json_encode', 'json_decode';
use VNDBUtil 'gtintype';
use SkinFile;
@@ -54,6 +55,7 @@ TUWF::set(
uname => { regex => qr/^[a-z0-9-]*$/, minlength => 2, maxlength => 15 },
gtin => { func => \&gtintype },
editsum => { maxlength => 5000, minlength => 2 },
+ json => { func => \&json_validate, inherit => ['json_fields'], default => [] },
},
);
TUWF::load_recursive('VNDB::Util', 'VNDB::DB', 'VNDB::Handler');
@@ -131,3 +133,24 @@ sub logformat {
$self->authInfo->{id} ? 'u'.$self->authInfo->{id} : '-', $msg;
}
+
+# 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.
+sub json_validate {
+ my($val, $opts) = @_;
+ my $fields = $opts->{json_fields};
+ my $data = eval { json_decode $val };
+ return 0 if $@ || ref $data ne 'ARRAY';
+ my %known_fields = map +($_->{field},1), @$fields;
+ 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};
+ }
+
+ $_[0] = json_encode $data;
+ return 1;
+}