diff options
-rw-r--r-- | elm/Lib/Api.elm | 1 | ||||
-rw-r--r-- | elm/Lib/Autocomplete.elm | 15 | ||||
-rw-r--r-- | elm/VNEdit.elm | 70 | ||||
-rw-r--r-- | lib/VNWeb/Elm.pm | 7 | ||||
-rw-r--r-- | lib/VNWeb/Staff/Elm.pm | 25 | ||||
-rw-r--r-- | lib/VNWeb/VN/Edit.pm | 22 |
6 files changed, 129 insertions, 11 deletions
diff --git a/elm/Lib/Api.elm b/elm/Lib/Api.elm index e09f1199..fd4a3a7e 100644 --- a/elm/Lib/Api.elm +++ b/elm/Lib/Api.elm @@ -51,6 +51,7 @@ showResponse res = TraitResult _ -> unexp VNResult _ -> unexp ProducerResult _ -> unexp + StaffResult _ -> unexp CharResult _ -> unexp AnimeResult _ -> unexp ImageResult _ -> unexp diff --git a/elm/Lib/Autocomplete.elm b/elm/Lib/Autocomplete.elm index 7f44ccae..13aacb5f 100644 --- a/elm/Lib/Autocomplete.elm +++ b/elm/Lib/Autocomplete.elm @@ -9,6 +9,7 @@ module Lib.Autocomplete exposing , traitSource , vnSource , producerSource + , staffSource , charSource , animeSource , init @@ -36,6 +37,7 @@ import Gen.Tags as GT import Gen.Traits as GTR import Gen.VN as GV import Gen.Producers as GP +import Gen.Staff as GS import Gen.Chars as GC import Gen.Anime as GA @@ -149,6 +151,19 @@ producerSource = } +staffSource : SourceConfig m GApi.ApiStaffResult +staffSource = + { source = Endpoint (\s -> GS.send { search = s }) + <| \x -> case x of + GApi.StaffResult e -> Just e + _ -> Nothing + , view = \i -> + [ b [ class "grayedout" ] [ text <| "s" ++ String.fromInt i.id ++ ": " ] + , text i.name ] + , key = \i -> String.fromInt i.aid + } + + charSource : SourceConfig m GApi.ApiCharResult charSource = { source = Endpoint (\s -> GC.send { search = s }) diff --git a/elm/VNEdit.elm b/elm/VNEdit.elm index 35b6d688..54247622 100644 --- a/elm/VNEdit.elm +++ b/elm/VNEdit.elm @@ -53,11 +53,13 @@ type alias Model = , length : Int , lWikidata : Maybe Int , lRenai : String + , vns : List GVE.RecvRelations + , vnSearch : A.Model GApi.ApiVNResult , anime : List GVE.RecvAnime , animeSearch : A.Model GApi.ApiAnimeResult , image : Img.Image - , vns : List GVE.RecvRelations - , vnSearch : A.Model GApi.ApiVNResult + , staff : List GVE.RecvStaff + , staffSearch : A.Model GApi.ApiStaffResult , screenshots : List (Int,Img.Image,Maybe Int) -- internal id, img, rel , scrUplRel : Maybe Int , scrUplNum : Maybe Int @@ -84,6 +86,8 @@ init d = , anime = d.anime , animeSearch = A.init "" , image = Img.info d.image_info + , staff = d.staff + , staffSearch = A.init "" , screenshots = List.indexedMap (\n i -> (n, Img.info (Just i.info), i.rid)) d.screenshots , scrUplRel = Nothing , scrUplNum = Nothing @@ -109,14 +113,18 @@ encode model = , relations = List.map (\v -> { vid = v.vid, relation = v.relation, official = v.official }) model.vns , anime = List.map (\a -> { aid = a.aid }) model.anime , image = model.image.id + , staff = List.map (\s -> { aid = s.aid, role = s.role, note = s.note }) model.staff , screenshots = List.map (\(_,i,r) -> { scr = Maybe.withDefault "" i.id, rid = r }) model.screenshots } +vnConfig : A.Config Msg GApi.ApiVNResult +vnConfig = { wrap = VNSearch, id = "relationadd", source = A.vnSource } + animeConfig : A.Config Msg GApi.ApiAnimeResult animeConfig = { wrap = AnimeSearch, id = "animeadd", source = A.animeSource } -vnConfig : A.Config Msg GApi.ApiVNResult -vnConfig = { wrap = VNSearch, id = "relationadd", source = A.vnSource } +staffConfig : A.Config Msg GApi.ApiStaffResult +staffConfig = { wrap = StaffSearch, id = "staffadd", source = A.staffSource } type Msg = Editsum Editsum.Msg @@ -140,6 +148,10 @@ type Msg | ImageSelect | ImageSelected File | ImageMsg Img.Msg + | StaffDel Int + | StaffRole Int String + | StaffNote Int String + | StaffSearch (A.Msg GApi.ApiStaffResult) | ScrUplRel (Maybe Int) | ScrUplSel | ScrUpl File (List File) @@ -188,6 +200,15 @@ update msg model = ImageSelected f -> let (nm, nc) = Img.upload Api.Cv f in ({ model | image = nm }, Cmd.map ImageMsg nc) ImageMsg m -> let (nm, nc) = Img.update m model.image in ({ model | image = nm }, Cmd.map ImageMsg nc) + StaffDel idx -> ({ model | staff = delidx idx model.staff }, Cmd.none) + StaffRole idx v -> ({ model | staff = modidx idx (\s -> { s | role = v }) model.staff }, Cmd.none) + StaffNote idx v -> ({ model | staff = modidx idx (\s -> { s | note = v }) model.staff }, Cmd.none) + StaffSearch m -> + let (nm, c, res) = A.update staffConfig m model.staffSearch + in case res of + Nothing -> ({ model | staffSearch = nm }, c) + Just s -> ({ model | staffSearch = A.clear nm "", staff = model.staff ++ [{ id = s.id, aid = s.aid, name = s.name, original = s.original, role = "staff", note = "" }] }, Cmd.none) + ScrUplRel s -> ({ model | scrUplRel = s }, Cmd.none) ScrUplSel -> (model, FSel.files ["image/png", "image/jpg"] ScrUpl) ScrUpl f1 fl -> @@ -220,6 +241,7 @@ isValid model = not ( (model.title /= "" && model.title == model.original) || not (Img.isValid model.image) || List.any (\(_,i,r) -> r == Nothing || not (Img.isValid i)) model.screenshots + || hasDuplicates (List.map (\s -> (s.aid, s.role)) model.staff) ) @@ -304,6 +326,44 @@ view model = ] ] ] + staff = + let + head = + if List.isEmpty model.staff then [] else [ + thead [] [ tr [] + [ td [] [] + , td [] [ text "Staff" ] + , td [] [ text "Role" ] + , td [] [ text "Note" ] + , td [] [] + ] ] ] + foot = + tfoot [] [ tr [] [ td [] [], td [ colspan 4 ] + [ br [] [] + , if hasDuplicates (List.map (\s -> (s.aid, s.role)) model.staff) + then b [ class "standout" ] [ text "List contains duplicate staff roles.", br [] [] ] + else text "" + , A.view staffConfig model.staffSearch [placeholder "Add staff..."] + , text "Can't find the person you're looking for? You can " + , a [ href "/s/new" ] [ text "create a new entry" ] + , text ", but " + , a [ href "/s/all" ] [ text "please check for aliasses first." ] + , br_ 2 + , text "Some guidelines:" + , ul [] + [ li [] [ text "Please add major staff only, i.e. people who had a significant and noticable impact on the work." ] + , li [] [ text "If one person performed several roles, you can add multiple entries with different major roles." ] + ] + ] ] ] + item n s = tr [] + [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| "s" ++ String.fromInt s.id ++ ":" ] ] + , td [] [ a [ href <| "/s" ++ String.fromInt s.id ] [ text s.name ] ] + , td [] [ inputSelect "" s.role (StaffRole n) [style "width" "150px" ] GT.creditTypes ] + , td [] [ inputText "" s.note (StaffNote n) (style "width" "300px" :: GVE.valStaffNote) ] + , td [] [ inputButton "remove" (StaffDel n) [] ] + ] + in table [] <| head ++ [ foot ] ++ List.indexedMap item model.staff + screenshots = let showrel r = "[" ++ (RDate.format (RDate.expand r.released)) ++ " " ++ (String.join "," r.lang) ++ "] " ++ r.title ++ " (r" ++ String.fromInt r.id ++ ")" @@ -397,7 +457,7 @@ view model = ] , div [ class "mainbox", classList [("hidden", model.tab /= General && model.tab /= All)] ] [ h1 [] [ text "General info" ], table [ class "formtable" ] geninfo ] , div [ class "mainbox", classList [("hidden", model.tab /= Image && model.tab /= All)] ] [ h1 [] [ text "Image" ], image ] - , div [ class "mainbox", classList [("hidden", model.tab /= Staff && model.tab /= All)] ] [ h1 [] [ text "Staff" ] ] + , div [ class "mainbox", classList [("hidden", model.tab /= Staff && model.tab /= All)] ] [ h1 [] [ text "Staff" ], staff ] , div [ class "mainbox", classList [("hidden", model.tab /= Cast && model.tab /= All)] ] [ h1 [] [ text "Cast" ] ] , div [ class "mainbox", classList [("hidden", model.tab /= Screenshots && model.tab /= All)] ] [ h1 [] [ text "Screenshots" ], screenshots ] , div [ class "mainbox" ] [ fieldset [ class "submit" ] diff --git a/lib/VNWeb/Elm.pm b/lib/VNWeb/Elm.pm index a2fdddb3..3625ba57 100644 --- a/lib/VNWeb/Elm.pm +++ b/lib/VNWeb/Elm.pm @@ -94,6 +94,12 @@ our %apis = ( name => {}, original => { required => 0, default => '' }, } } ], + StaffResult => [ { aoh => { # Response to 'Staff' + id => { id => 1 }, + aid => { id => 1 }, + name => {}, + original => { required => 0, default => '' }, + } } ], CharResult => [ { aoh => { # Response to 'Chars' id => { id => 1 }, name => {}, @@ -405,6 +411,7 @@ sub write_types { $data .= def charRoles => 'List (String, String)' => list map tuple(string $_, string $CHAR_ROLE{$_}{txt}), keys %CHAR_ROLE; $data .= def vnLengths => 'List (Int, String)' => list map tuple($_, string $VN_LENGTH{$_}{txt}.($VN_LENGTH{$_}{time}?" ($VN_LENGTH{$_}{time})":'')), keys %VN_LENGTH; $data .= def vnRelations=> 'List (String, String)' => list map tuple(string $_, string $VN_RELATION{$_}{txt}), keys %VN_RELATION; + $data .= def creditTypes=> 'List (String, String)' => list map tuple(string $_, string $CREDIT_TYPE{$_}), keys %CREDIT_TYPE; $data .= def curYear => Int => (gmtime)[5]+1900; write_module Types => $data; diff --git a/lib/VNWeb/Staff/Elm.pm b/lib/VNWeb/Staff/Elm.pm new file mode 100644 index 00000000..da40f8a5 --- /dev/null +++ b/lib/VNWeb/Staff/Elm.pm @@ -0,0 +1,25 @@ +package VNWeb::Staff::Elm; + +use VNWeb::Prelude; + +elm_api Staff => undef, { search => {} }, sub { + my $q = shift->{search}; + my $qs = $q =~ s/[%_]//gr; + + elm_StaffResult tuwf->dbPagei({ results => 15, page => 1 }, + 'SELECT s.id, sa.aid, sa.name, sa.original + FROM (', + sql_join('UNION ALL', + $q =~ /^$RE{sid}$/ ? sql('SELECT 0, aid FROM staff_alias WHERE id =', \"$+{id}") : (), + sql('SELECT 1+substr_score(lower(name),', \$qs, ')+substr_score(lower(original),', \$qs, '), aid + FROM staff_alias WHERE name ILIKE', \"%$qs%", 'OR original ILIKE', \"%$qs%"), + ), ') x(prio, aid) + JOIN staff_alias sa ON sa.aid = x.aid + JOIN staff s ON s.id = sa.id + WHERE NOT s.hidden + GROUP BY s.id, sa.aid, sa.name, sa.original + ORDER BY MIN(x.prio), sa.name + '); +}; + +1; diff --git a/lib/VNWeb/VN/Edit.pm b/lib/VNWeb/VN/Edit.pm index 7182d8d3..cf3e7fba 100644 --- a/lib/VNWeb/VN/Edit.pm +++ b/lib/VNWeb/VN/Edit.pm @@ -13,6 +13,13 @@ my $FORM = { length => { uint => 1, enum => \%VN_LENGTH }, l_wikidata => { required => 0, uint => 1, max => (1<<31)-1 }, l_renai => { required => 0, default => '', maxlength => 100 }, + relations => { sort_keys => 'vid', aoh => { + vid => { id => 1 }, + relation => { enum => \%VN_RELATION }, + official => { anybool => 1 }, + title => { _when => 'out' }, + original => { _when => 'out', required => 0, default => '' }, + } }, anime => { sort_keys => 'aid', aoh => { aid => { id => 1 }, title => { _when => 'out' }, @@ -20,11 +27,12 @@ my $FORM = { } }, image => { required => 0, vndbid => 'cv' }, image_info => { _when => 'out', required => 0, type => 'hash', keys => $VNWeb::Elm::apis{ImageResult}[0]{aoh} }, - relations => { sort_keys => 'vid', aoh => { - vid => { id => 1 }, - relation => { enum => \%VN_RELATION }, - official => { anybool => 1 }, - title => { _when => 'out' }, + staff => { sort_keys => ['aid','role'], aoh => { + aid => { id => 1 }, + role => { enum => \%CREDIT_TYPE }, + note => { required => 0, default => '', maxlength => 250 }, + id => { _when => 'out', id => 1 }, + name => { _when => 'out' }, original => { _when => 'out', required => 0, default => '' }, } }, screenshots=> { sort_keys => 'scr', aoh => { @@ -62,9 +70,10 @@ TUWF::get qr{/$RE{vrev}/edit} => sub { $_->{info} = {id=>$_->{scr}} for $e->{screenshots}->@*; enrich_image 0, [map $_->{info}, $e->{screenshots}->@*]; + enrich_merge vid => 'SELECT id AS vid, title, original FROM vn WHERE id IN', $e->{relations}; enrich_merge aid => 'SELECT id AS aid, title_romaji AS title, title_kanji AS original FROM anime WHERE id IN', $e->{anime}; - enrich_merge vid => 'SELECT id AS vid, title, original FROM vn WHERE id IN', $e->{relations}; + enrich_merge aid => 'SELECT id, aid, name, original FROM staff_alias WHERE aid IN', $e->{staff}; $e->{releases} = tuwf->dbAlli(' SELECT rv.vid, r.id, r.title, r.original, r.released, r.type as rtype, r.reso_x, r.reso_y @@ -113,6 +122,7 @@ elm_api VNEdit => $FORM_OUT, $FORM_IN, sub { validate_dbid 'SELECT id FROM anime WHERE id IN', map $_->{aid}, $data->{anime}->@*; validate_dbid 'SELECT id FROM images WHERE id IN', $data->{image} if $data->{image}; validate_dbid 'SELECT id FROM images WHERE id IN', map $_->{scr}, $data->{screenshots}->@*; + validate_dbid 'SELECT aid FROM staff_alias WHERE aid IN', map $_->{aid}, $data->{staff}->@*; $data->{relations} = [] if $data->{hidden}; validate_dbid 'SELECT id FROM vn WHERE id IN', map $_->{vid}, $data->{relations}->@*; |