summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2015-09-17 16:21:41 +0200
committerYorhel <git@yorhel.nl>2015-09-17 16:21:41 +0200
commita16c4bbbbd97fecb7a02a535efce0fefb1424ca9 (patch)
treedf529c5a881dc0b32cc0be2a4f16ab02f960eb11
parent108c2a8000d1e525c18a4deb3b5412639bda1e3c (diff)
Created json_validate() for JSON form data, used for Staff alias editor
The intention is to move more JS editing forms to use JSON, but manually verifying JSON objects is both painful and likely to introduce errors or vulnerabilities. json_validate() is a bit of a hack, but has the advantage that its validation syntax is the same as for normal forms, and it automatically strips whitespace. I intent to give kv_validate() an upgrade to be more flexible/modular so it can do more custom normalization. But that's for later. I've been meaning to rewrite the JS forms anyway together with the large JS rewrite, but I'm rather lazy. This is one small step in the right direction anyway. Note that json_validate() assumes that the JS code will provide user-friendly messages on bad input, but the staff alias editor doesn't quite do this yet.
-rw-r--r--lib/VNDB/DB/Staff.pm11
-rw-r--r--lib/VNDB/Func.pm30
-rw-r--r--lib/VNDB/Handler/Staff.pm28
3 files changed, 44 insertions, 25 deletions
diff --git a/lib/VNDB/DB/Staff.pm b/lib/VNDB/DB/Staff.pm
index 1b9a10da..4dfe0756 100644
--- a/lib/VNDB/DB/Staff.pm
+++ b/lib/VNDB/DB/Staff.pm
@@ -126,7 +126,7 @@ sub dbStaffRevisionInsert {
my($self, $o) = @_;
$self->dbExec('DELETE FROM edit_staff_aliases');
- if ($o->{aid}) {
+ if($o->{aid}) {
$self->dbExec(q|
INSERT INTO edit_staff_aliases (id, name, original) VALUES (?, ?, ?)|,
$o->{aid}, $o->{name}, $o->{original});
@@ -139,12 +139,11 @@ sub dbStaffRevisionInsert {
my %staff = map exists($o->{$_}) ? (qq|"$_" = ?|, $o->{$_}) : (),
qw|aid gender lang desc l_wp l_site l_twitter l_anidb|;
$self->dbExec('UPDATE edit_staff !H', \%staff) if %staff;
- for my $alias (@{$o->{aliases}}) {
- if ($alias->[0]) {
- $self->dbExec('INSERT INTO edit_staff_aliases (id, name, original) VALUES (!l)', $alias);
+ for my $a (@{$o->{aliases}}) {
+ if($a->{aid}) {
+ $self->dbExec('INSERT INTO edit_staff_aliases (id, name, original) VALUES (!l)', [ @{$a}{qw|aid name orig|} ]);
} else {
- $self->dbExec('INSERT INTO edit_staff_aliases (name, original) VALUES (?, ?)',
- $alias->[1], $alias->[2]);
+ $self->dbExec('INSERT INTO edit_staff_aliases (name, original) VALUES (?, ?)', $a->{name}, $a->{orig});
}
}
}
diff --git a/lib/VNDB/Func.pm b/lib/VNDB/Func.pm
index ac9fdd58..dd3f292e 100644
--- a/lib/VNDB/Func.pm
+++ b/lib/VNDB/Func.pm
@@ -3,7 +3,7 @@ package VNDB::Func;
use strict;
use warnings;
-use TUWF ':html';
+use TUWF ':html', 'kv_validate';
use Exporter 'import';
use POSIX 'strftime', 'ceil', 'floor';
use JSON::XS;
@@ -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
- jsonEncode jsonDecode script_json
+ jsonEncode jsonDecode script_json json_validate
mtvoiced mtani mtvnlen mtrlstat mtvnlstat mtbloodt
|);
@@ -228,6 +228,32 @@ 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 { jsonDecode $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 3c8fd7af..2840442b 100644
--- a/lib/VNDB/Handler/Staff.pm
+++ b/lib/VNDB/Handler/Staff.pm
@@ -215,29 +215,23 @@ sub edit {
{ post => 'ilock', required => 0 },
);
push @{$frm->{_err}}, 'badeditsum' if !$frm->{editsum} || lc($frm->{editsum}) eq lc($frm->{desc});
+ my $aliases = json_validate($frm, 'aliases',
+ { field => 'name', required => 1, maxlength => 200 },
+ { field => 'orig', required => 0, maxlength => 200, default => '' },
+ { field => 'aid', required => 0, template => 'int', default => 0 },
+ );
- my @aliases;
- my $raw_a = eval { jsonDecode $frm->{aliases} };
- push @{$frm->{_err}}, [ 'aliases', 'template', 'json' ] if $@ || ref $raw_a ne 'ARRAY';
if(!$frm->{_err}) {
+ $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}};
- for my $a (sort { $a->{name} cmp $b->{name} } @$raw_a) {
- # check for empty aliases
- if($a->{name} =~ /^\s*$/) {
- push @{$frm->{_err}}, ['alias_name', 'required'];
- last;
- }
- s/^\s+|\s+$//g for ($a->{name}, $a->{orig});
- # normalize alias id to a number so that the comparison works
- # or reset it to zero for newly added aliases.
- $a->{aid} *= $old_aliases{$a->{aid}} ? 1 : 0;
- push @aliases, $a;
- }
+ # normalize alias id to a number so that the comparison works
+ # or reset it 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} = jsonEncode \@aliases;
+ $frm->{aliases} = jsonEncode $aliases;
$frm->{ihid} = $frm->{ihid} ?1:0;
$frm->{ilock} = $frm->{ilock}?1:0;
$frm->{aid} = $frm->{primary} if $sid;
@@ -246,7 +240,7 @@ sub edit {
return $self->resRedirect("/s$sid", 'post')
if $sid && !first { ($frm->{$_}//'') ne ($b4{$_}//'') } keys %b4;
- $frm->{aliases} = [ map [ @{$_}{qw|aid name orig|} ], @aliases ];
+ $frm->{aliases} = $aliases;
my $nrev = $self->dbItemEdit ('s' => $sid ? $s->{cid} : undef, %$frm);
return $self->resRedirect("/s$nrev->{iid}.$nrev->{rev}", 'post');
}