From d735e66d7d9b2d8c9a965ec96753864ff8c306c2 Mon Sep 17 00:00:00 2001 From: Yorhel Date: Wed, 25 Sep 2019 18:37:29 +0200 Subject: v2rw: Add Elm & db_edit framework + Convert doc page editing Most of this is copied from v3. I did improve on a few aspects: - db_edit() and db_entry() use VNDB::Schema rather than dynamically querying the DB. This has the minor advantage of a faster startup. - The Elm code generator now writes to multiple files, this avoids the namespace pollution seen in v3's Lib.Gen and makes the dependency graph a bit more lean (i.e. faster incremental builds). - The Elm code generator doesn't update the timestamp of files that haven't been modified. This also speeds up incremental builds, the elm compiler can now skip rebuilding unmodified files. - The Elm API response generator code now uses plain functions rather than code references and all possible responses are now defined in Elm.pm. Turns out most API responses were used from more than a single place, so it makes sense to have them centrally defined. The doc page preview function is also much nicer; I'd like to apply this to all BBCode textareas as well. (Elm.pm itself is ugly as hell though. And we will prolly need some HTML form generation functions in Elm to make that part less verbose) --- lib/VNWeb/Validation.pm | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'lib/VNWeb/Validation.pm') diff --git a/lib/VNWeb/Validation.pm b/lib/VNWeb/Validation.pm index a014b11d..80af1d34 100644 --- a/lib/VNWeb/Validation.pm +++ b/lib/VNWeb/Validation.pm @@ -6,10 +6,76 @@ use VNWeb::Auth; use Exporter 'import'; our @EXPORT = qw/ + form_compile + form_changed can_edit /; +TUWF::set custom_validations => { + id => { uint => 1, max => 1<<40 }, + editsum => { required => 1, length => [ 2, 5000 ] }, +}; + + +# Recursively remove keys from hashes that have a '_when' key that doesn't +# match $when. This is a quick and dirty way to create multiple validation +# schemas from a single schema. For example: +# +# { +# title => { _when => 'input' }, +# name => { }, +# } +# +# If $when is 'input', then this function returns: +# { title => {}, name => {} } +# Otherwise, it returns: +# { name => {} } +sub _stripwhen { + my($when, $o) = @_; + return $o if ref $o ne 'HASH'; + +{ map $_ eq '_when' || (ref $o->{$_} eq 'HASH' && defined $o->{$_}{_when} && $o->{$_}{_when} !~ $when) ? () : ($_, _stripwhen($when, $o->{$_})), keys %$o } +} + + +# Short-hand to compile a validation schema for a form. Usage: +# +# form_compile $when, { +# title => { _when => 'input' }, +# name => { }, +# .. +# }; +sub form_compile { + tuwf->compile({ type => 'hash', keys => _stripwhen @_ }); +} + + +sub _eq_deep { + my($a, $b) = @_; + return 0 if ref $a ne ref $b; + return 0 if defined $a != defined $b; + return 1 if !defined $a; + return 1 if !ref $a && $a eq $b; + return 1 if ref $a eq 'ARRAY' && (@$a == @$b && !grep !_eq_deep($a->[$_], $b->[$_]), 0..$#$a); + return 1 if ref $a eq 'HASH' && _eq_deep([sort keys %$a], [sort keys %$b]) && !grep !_eq_deep($a->{$_}, $b->{$_}), keys %$a; + 0 +} + + +# Usage: form_changed $schema, $a, $b +# Returns 1 if there is a difference between the data ($a) and the form input +# ($b), using the normalization defined in $schema. The $schema must validate. +sub form_changed { + my($schema, $a, $b) = @_; + my $na = $schema->validate($a)->data; + my $nb = $schema->validate($b)->data; + + #warn "a=".JSON::XS->new->pretty->canonical->encode($na); + #warn "b=".JSON::XS->new->pretty->canonical->encode($nb); + !_eq_deep $na, $nb; +} + + # Returns whether the current user can edit the given database entry. sub can_edit { my($type, $entry) = @_; -- cgit v1.2.3