diff options
-rw-r--r-- | elm/ReleaseEdit/Main.elm | 64 | ||||
-rw-r--r-- | elm/ReleaseEdit/New.elm | 13 | ||||
-rw-r--r-- | lib/VNDB/ExtLinks.pm | 4 | ||||
-rw-r--r-- | lib/VNDB/Handler/Releases.pm | 2 | ||||
-rw-r--r-- | lib/VNWeb/Elm.pm | 23 | ||||
-rw-r--r-- | lib/VNWeb/Releases/Edit.pm | 92 |
6 files changed, 138 insertions, 60 deletions
diff --git a/elm/ReleaseEdit/Main.elm b/elm/ReleaseEdit/Main.elm index a24d34fe..acab0825 100644 --- a/elm/ReleaseEdit/Main.elm +++ b/elm/ReleaseEdit/Main.elm @@ -1,4 +1,4 @@ -module ReleaseEdit.Main exposing (Model, Msg, main, view, update) +module ReleaseEdit.Main exposing (Model, Msg, main, new, view, update, sub) import Html exposing (..) import Html.Events exposing (..) @@ -26,7 +26,7 @@ main = Browser.element { init = \e -> (init e, Cmd.none) , view = view , update = update - , subscriptions = \m -> Sub.batch [ DD.sub m.langDd, DD.sub m.platDd ] + , subscriptions = sub } @@ -67,6 +67,17 @@ type alias Model = } +engineConf : List GRE.RecvEngines -> A.Config Msg GRE.RecvEngines +engineConf lst = + { wrap = Engine + , id = "engine" + , source = + { source = A.Func (\s -> List.filter (\e -> String.contains (String.toLower s) (String.toLower e.engine)) lst |> List.take 10) + , view = \i -> [ text i.engine, b [ class "grayedout" ] [ text <| " (" ++ String.fromInt i.count ++ ")" ] ] + , key = \i -> i.engine + } + } + init : GRE.Recv -> Model init d = { state = Api.Normal @@ -92,14 +103,9 @@ init d = , ani_story = d.ani_story , ani_ero = d.ani_ero , website = d.website - , engineConf = { wrap = Engine - , id = "engine" - , source = { source = A.Func (\s -> List.filter (\e -> String.contains (String.toLower s) (String.toLower e.engine)) d.engines |> List.take 10) - , view = \i -> [ text i.engine, b [ class "grayedout" ] [ text <| " (" ++ String.fromInt i.count ++ ")" ] ] - , key = \i -> i.engine } - } + , engineConf = engineConf d.engines , engine = A.init d.engine - , extlinks = EL.new d.extlinks GEL.releaseLinks + , extlinks = EL.new d.extlinks GEL.releaseSites , vn = d.vn , vnAdd = A.init "" , prod = d.producers @@ -110,6 +116,44 @@ init d = } +new : GRE.New -> Model +new d = + { state = Api.Normal + , title = d.title + , original = d.original + , rtype = "complete" + , patch = False + , freeware = False + , doujin = False + , lang = Set.empty + , langDd = DD.init "lang" LangOpen + , plat = Set.empty + , platDd = DD.init "platforms" PlatOpen + , media = [] + , gtinInput = formatGtin 0 + , gtin = 0 + , catalog = "" + , released = 99999999 -- TODO: Would be nice to set this to 'unknown' and force the user to change it + , minage = -1 + , uncensored = False + , resolution = "unknown" + , voiced = 0 + , ani_story = 0 + , ani_ero = 0 + , website = "" + , engineConf = engineConf d.engines + , engine = A.init "" + , extlinks = EL.new GEL.releaseNew GEL.releaseSites + , vn = d.vn + , vnAdd = A.init "" + , prod = [] + , prodAdd = A.init "" + , notes = TP.bbcode "" + , editsum = Editsum.new + , id = Nothing + } + + encode : Model -> GRE.Send encode model = { id = model.id @@ -148,6 +192,8 @@ vnConfig = { wrap = VNSearch, id = "vnadd", source = A.vnSource } producerConfig : A.Config Msg GApi.ApiProducerResult producerConfig = { wrap = ProdSearch, id = "prodadd", source = A.producerSource } +sub : Model -> Sub Msg +sub m = Sub.batch [ DD.sub m.langDd, DD.sub m.platDd ] type Msg = Title String diff --git a/elm/ReleaseEdit/New.elm b/elm/ReleaseEdit/New.elm new file mode 100644 index 00000000..ac34be8c --- /dev/null +++ b/elm/ReleaseEdit/New.elm @@ -0,0 +1,13 @@ +module ReleaseEdit.New exposing (main) + +import Browser +import ReleaseEdit.Main as Main +import Gen.ReleaseEdit as GRE + +main : Program GRE.New Main.Model Main.Msg +main = Browser.element + { init = \n -> (Main.new n, Cmd.none) + , view = Main.view + , update = Main.update + , subscriptions = Main.sub + } diff --git a/lib/VNDB/ExtLinks.pm b/lib/VNDB/ExtLinks.pm index 4c8ea413..9f73b51d 100644 --- a/lib/VNDB/ExtLinks.pm +++ b/lib/VNDB/ExtLinks.pm @@ -304,7 +304,7 @@ sub validate_extlinks { # Returns a list of sites for use in VNWeb::Elm: -# { id => $id, name => $label, fmt => $label, regex => $regex, int => $bool, multi => $bool, default => 0||'""' } +# { id => $id, name => $label, fmt => $label, regex => $regex, int => $bool, multi => $bool, default => 0||'""'||'[]' } sub extlinks_sites { my($type) = @_; my($schema) = grep +($_->{dbentry_type}||'') eq $type, values VNDB::Schema::schema->%*; @@ -313,7 +313,7 @@ sub extlinks_sites { my($s) = grep $_->{name} eq $f, $schema->{cols}->@*; +{ id => $_, name => $p->{label}, fmt => $p->{fmt}, regex => full_regex($p->{regex}) , int => $s->{type} =~ /^int/?1:0, multi => $s->{type} =~ /\[\]/?1:0 - , default => $s->{type} =~ /^int/?0:'""' } + , default => $s->{type} =~ /\[\]/ ? '[]' : $s->{type} =~ /^int/ ? 0 : '""' } } sort grep $LINKS{$type}{$_}{regex}, keys $LINKS{$type}->%* } diff --git a/lib/VNDB/Handler/Releases.pm b/lib/VNDB/Handler/Releases.pm index fbdd0c9a..ef277f15 100644 --- a/lib/VNDB/Handler/Releases.pm +++ b/lib/VNDB/Handler/Releases.pm @@ -12,7 +12,7 @@ our @EXPORT = ('releaseExtLinks'); TUWF::register( - qr{(v)([1-9]\d*)/add} => \&edit, + qr{old/(v)([1-9]\d*)/add} => \&edit, qr{r} => \&browse, qr{old/r(?:([1-9]\d*)(?:\.([1-9]\d*))?/(edit|copy))} => \&edit, diff --git a/lib/VNWeb/Elm.pm b/lib/VNWeb/Elm.pm index cf6409cb..355fbdc2 100644 --- a/lib/VNWeb/Elm.pm +++ b/lib/VNWeb/Elm.pm @@ -202,7 +202,7 @@ sub write_module { # elm_api FormName => $OUT_SCHEMA, $IN_SCHEMA, sub { # my($data) = @_; # elm_Success # Or any other elm_Response() function -# }; +# }, %extra_schemas; # # That will create an endpoint at `POST /elm/FormName.json` that accepts JSON # data that must validate $IN_SCHEMA. The subroutine is given the validated @@ -220,11 +220,12 @@ sub write_module { # -- Command to send an API request to the endpoint and receive a response # send : Send -> (Gen.Api.Response -> msg) -> Cmd msg # +# Extra type aliases can be added using %extra_schemas. sub elm_api { - my($name, $out, $in, $sub) = @_; + my($name, $out, $in, $sub, %extra) = @_; - $in = ref $in eq 'HASH' ? tuwf->compile({ type => 'hash', keys => $in }) : $in; - $out = ref $out eq 'HASH' ? tuwf->compile({ type => 'hash', keys => $out }) : $out; + my sub comp { ref $_[0] eq 'HASH' ? tuwf->compile({ type => 'hash', keys => $_[0] }) : $_[0] } + $in = comp $in; TUWF::post qr{/elm/\Q$name\E\.json} => sub { if(!auth->csrfcheck(tuwf->reqHeader('X-CSRF-Token')||'')) { @@ -245,8 +246,9 @@ sub elm_api { if(tuwf->{elmgen}) { my $data = "import Gen.Api as GApi\n"; $data .= "import Lib.Api as Api\n"; - $data .= def_type Recv => $out->analyze if $out; + $data .= def_type Recv => comp($out)->analyze if $out; $data .= def_type Send => $in->analyze; + $data .= def_type $_ => comp($extra{$_})->analyze for sort keys %extra; $data .= def_validation val => $in->analyze; $data .= encoder encode => 'Send', $in->analyze; $data .= "send : Send -> (GApi.Response -> msg) -> Cmd msg\n"; @@ -352,8 +354,8 @@ sub write_extlinks { my sub links { my($name, $type, @links) = @_; - def $name => "List (Site $type)" => list map { - my($i,$l) = ($_, $links[$_]); + $data .= def $name.'Sites' => "List (Site $type)" => list map { + my $l = $_; my $addval = $l->{int} ? 'toint v' : 'v'; '{ '.join("\n , ", 'name = '.string($l->{name}), @@ -364,9 +366,12 @@ sub write_extlinks { 'del = (\i m -> { m | '.$l->{id}.' = '.($l->{multi} ? "delidx i m.$l->{id}" : $l->{default}).' })', 'add = (\v m -> { m | '.$l->{id}.' = '.($l->{multi} ? "m.$l->{id} ++ [$addval]" : $addval).' })' )."\n }"; - } 0..$#links; + } @links; + + $data .= def $name.'New' => $type => + "\n { ".join("\n , ", map sprintf('%-10s = %s', $_->{id}, $_->{default}), @links)."\n }"; } - $data .= links releaseLinks => 'GRE.RecvExtlinks' => VNDB::ExtLinks::extlinks_sites('r'); + links release => 'GRE.RecvExtlinks' => VNDB::ExtLinks::extlinks_sites('r'); write_module ExtLinks => $data; } diff --git a/lib/VNWeb/Releases/Edit.pm b/lib/VNWeb/Releases/Edit.pm index a292261d..f569e7b0 100644 --- a/lib/VNWeb/Releases/Edit.pm +++ b/lib/VNWeb/Releases/Edit.pm @@ -4,46 +4,46 @@ use VNWeb::Prelude; my $FORM = { - id => { required => 0, id => 1 }, - title => { maxlength => 250 }, - original => { required => 0, default => '', maxlength => 250 }, - rtype => { enum => \%RELEASE_TYPE }, - patch => { anybool => 1 }, - freeware => { anybool => 1 }, - doujin => { anybool => 1 }, - lang => { aoh => { lang => { enum => \%LANGUAGE } } }, - platforms => { aoh => { platform => { enum => \%PLATFORM } } }, - media => { aoh => { + id => { _when => 'in out', required => 0, id => 1 }, + title => { _when => 'in out new', maxlength => 250 }, + original => { _when => 'in out new', required => 0, default => '', maxlength => 250 }, + rtype => { _when => 'in out', enum => \%RELEASE_TYPE }, + patch => { _when => 'in out', anybool => 1 }, + freeware => { _when => 'in out', anybool => 1 }, + doujin => { _when => 'in out', anybool => 1 }, + lang => { _when => 'in out', aoh => { lang => { enum => \%LANGUAGE } } }, + platforms => { _when => 'in out', aoh => { platform => { enum => \%PLATFORM } } }, + media => { _when => 'in out', aoh => { medium => { enum => \%MEDIUM }, qty => { uint => 1, range => [0,20] }, } }, - gtin => { gtin => 1 }, - catalog => { required => 0, default => '', maxlength => 50 }, - released => { rdate => 1 }, - minage => { int => 1, enum => \%AGE_RATING }, - uncensored => { anybool => 1 }, - resolution => { enum => \%RESOLUTION }, - voiced => { uint => 1, enum => \%VOICED }, - ani_story => { uint => 1, enum => \%ANIMATED }, - ani_ero => { uint => 1, enum => \%ANIMATED }, - website => { required => 0, default => '', weburl => 1 }, - engine => { required => 0, default => '', maxlength => 50 }, - extlinks => validate_extlinks('r'), - notes => { required => 0, default => '', maxlength => 10240 }, - vn => { sort_keys => 'vid', aoh => { + gtin => { _when => 'in out', gtin => 1 }, + catalog => { _when => 'in out', required => 0, default => '', maxlength => 50 }, + released => { _when => 'in out', min => 1, rdate => 1 }, + minage => { _when => 'in out', int => 1, enum => \%AGE_RATING }, + uncensored => { _when => 'in out', anybool => 1 }, + resolution => { _when => 'in out', enum => \%RESOLUTION }, + voiced => { _when => 'in out', uint => 1, enum => \%VOICED }, + ani_story => { _when => 'in out', uint => 1, enum => \%ANIMATED }, + ani_ero => { _when => 'in out', uint => 1, enum => \%ANIMATED }, + website => { _when => 'in out', required => 0, default => '', weburl => 1 }, + engine => { _when => 'in out', required => 0, default => '', maxlength => 50 }, + extlinks => { _when => 'in out', validate_extlinks('r')->%* }, + notes => { _when => 'in out', required => 0, default => '', maxlength => 10240 }, + vn => { _when => 'in out new', sort_keys => 'vid', aoh => { vid => { id => 1 }, - title => { _when => 'out' }, + title => { _when => 'out new' }, } }, - producers => { sort_keys => 'pid', aoh => { + producers => { _when => 'in out', sort_keys => 'pid', aoh => { pid => { id => 1 }, developer => { anybool => 1 }, publisher => { anybool => 1 }, name => { _when => 'out' }, } }, - hidden => { anybool => 1 }, - locked => { anybool => 1 }, + hidden => { _when => 'in out', anybool => 1 }, + locked => { _when => 'in out', anybool => 1 }, - engines => { _when => 'out', aoh => { + engines => { _when => 'out new', aoh => { engine => {}, count => { uint => 1 }, } }, @@ -53,10 +53,18 @@ my $FORM = { my $FORM_OUT = form_compile out => $FORM; my $FORM_IN = form_compile in => $FORM; +my $FORM_NEW = form_compile new => $FORM; my $FORM_CMP = form_compile cmp => $FORM; sub to_extlinks { $_[0]{extlinks} = { map +($_, delete $_[0]{$_}), grep /^l_/, keys $_[0]->%* } } +sub engines { + tuwf->dbAlli(q{ + SELECT engine, count(*) AS count FROM releases WHERE NOT hidden AND engine <> '' + GROUP BY engine ORDER BY count(*) DESC, engine + }) +} + TUWF::get qr{/$RE{rrev}/(?<action>edit|copy)} => sub { my $e = db_entry r => tuwf->capture('id'), tuwf->capture('rev') or return tuwf->resNotFound; my $copy = tuwf->capture('action') eq 'copy'; @@ -64,12 +72,9 @@ TUWF::get qr{/$RE{rrev}/(?<action>edit|copy)} => sub { $e->{rtype} = delete $e->{type}; $e->{authmod} = auth->permDbmod; - $e->{editsum} = $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision r$e->{id}.$e->{chrev}"; + $e->{editsum} = $copy ? "Copied from r$e->{id}.$e->{chrev}" : $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision r$e->{id}.$e->{chrev}"; - $e->{engines} = tuwf->dbAlli(q{ - SELECT engine, count(*) AS count FROM releases WHERE NOT hidden AND engine <> '' - GROUP BY engine ORDER BY count(*) DESC, engine - }); + $e->{engines} = engines; to_extlinks $e; enrich_merge vid => 'SELECT id AS vid, title FROM vn WHERE id IN', $e->{vn}; @@ -86,11 +91,20 @@ TUWF::get qr{/$RE{rrev}/(?<action>edit|copy)} => sub { TUWF::get qr{/$RE{vid}/add}, sub { return tuwf->resDenied if !can_edit r => undef; - # TODO: Auto-fill some fields - framework_ title => 'Add release', + my $v = tuwf->dbRowi('SELECT id, title, original FROM vn WHERE id =', \tuwf->capture('id')); + return tuwf->resNotFound if !$v->{id}; + + # TODO: List deleted releases + framework_ title => "Add release to $v->{title}", sub { - editmsg_ r => undef, 'Add release'; - elm_ 'ReleaseEdit.New'; + editmsg_ r => undef, "Add release to $v->{title}"; + elm_ 'ReleaseEdit.New' => $FORM_NEW, { + title => $v->{title}, + original => $v->{original}, + engines => engines(), + authmod => auth->permDbmod(), + vn => [{vid => $v->{id}, title => $v->{title}}], + }; }; }; @@ -123,7 +137,7 @@ elm_api ReleaseEdit => $FORM_OUT, $FORM_IN, sub { my($id,undef,$rev) = db_edit r => $e->{id}, $data; elm_Redirect "/r$id.$rev"; -}; +}, New => $FORM_NEW; 1; |