summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--elm/Lib/Api.elm1
-rw-r--r--elm/Lib/Autocomplete.elm15
-rw-r--r--elm/VNEdit.elm70
-rw-r--r--lib/VNWeb/Elm.pm7
-rw-r--r--lib/VNWeb/Staff/Elm.pm25
-rw-r--r--lib/VNWeb/VN/Edit.pm22
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}->@*;