summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--css/skins/air.sass2
-rw-r--r--css/skins/angel.sass2
-rw-r--r--css/skins/aselia_01.sass2
-rw-r--r--css/skins/carnevale.sass2
-rw-r--r--css/skins/eiel.sass2
-rw-r--r--css/skins/ever17_01.sass2
-rw-r--r--css/skins/fate_01.sass2
-rw-r--r--css/skins/fate_02.sass2
-rw-r--r--css/skins/grey.sass2
-rw-r--r--css/skins/higanbana.sass2
-rw-r--r--css/skins/higu.sass2
-rw-r--r--css/skins/lb.sass2
-rw-r--r--css/skins/lb_02.sass2
-rw-r--r--css/skins/primitive.sass2
-rw-r--r--css/skins/saya.sass2
-rw-r--r--css/skins/seinarukana.sass2
-rw-r--r--css/skins/taka.sass2
-rw-r--r--css/skins/teal.sass2
-rw-r--r--css/skins/term.sass2
-rw-r--r--css/skins/tsukihime.sass2
-rw-r--r--css/skins/tsukihime_02.sass2
-rw-r--r--elm/AdvSearch/Fields.elm2
-rw-r--r--elm/AdvSearch/Lib.elm6
-rw-r--r--elm/AdvSearch/Main.elm2
-rw-r--r--elm/AdvSearch/Producers.elm8
-rw-r--r--elm/AdvSearch/Set.elm2
-rw-r--r--elm/AdvSearch/Staff.elm8
-rw-r--r--elm/CharEdit.elm38
-rw-r--r--elm/Discussions/Edit.elm12
-rw-r--r--elm/DocEdit.elm4
-rw-r--r--elm/ImageFlagging.elm2
-rw-r--r--elm/Lib/Autocomplete.elm18
-rw-r--r--elm/Lib/Util.elm7
-rw-r--r--elm/ProducerEdit.elm8
-rw-r--r--elm/ReleaseEdit.elm10
-rw-r--r--elm/Reviews/Edit.elm14
-rw-r--r--elm/StaffEdit.elm2
-rw-r--r--elm/Tagmod.elm6
-rw-r--r--elm/UList/LabelEdit.elm6
-rw-r--r--elm/UList/ManageLabels.elm2
-rw-r--r--elm/UList/Opt.elm18
-rw-r--r--elm/UList/ReleaseEdit.elm10
-rw-r--r--elm/UList/SaveDefault.elm2
-rw-r--r--elm/UList/VNPage.elm2
-rw-r--r--elm/UList/VoteEdit.elm4
-rw-r--r--elm/User/Edit.elm4
-rw-r--r--elm/User/PassSet.elm2
-rw-r--r--elm/VNEdit.elm46
-rw-r--r--lib/Multi/API.pm205
-rw-r--r--lib/Multi/IRC.pm98
-rw-r--r--lib/Multi/Maintenance.pm2
-rw-r--r--lib/VNDB/BBCode.pm8
-rw-r--r--lib/VNDB/ExtLinks.pm4
-rw-r--r--lib/VNDB/Func.pm23
-rw-r--r--lib/VNDB/Skins.pm2
-rw-r--r--lib/VNWeb/AdvSearch.pm16
-rw-r--r--lib/VNWeb/Auth.pm4
-rw-r--r--lib/VNWeb/Chars/Edit.pm28
-rw-r--r--lib/VNWeb/Chars/List.pm14
-rw-r--r--lib/VNWeb/Chars/Page.pm30
-rw-r--r--lib/VNWeb/Chars/VNTab.pm4
-rw-r--r--lib/VNWeb/DB.pm13
-rw-r--r--lib/VNWeb/Discussions/Board.pm15
-rw-r--r--lib/VNWeb/Discussions/Edit.pm18
-rw-r--r--lib/VNWeb/Discussions/Elm.pm8
-rw-r--r--lib/VNWeb/Discussions/Index.pm2
-rw-r--r--lib/VNWeb/Discussions/Lib.pm4
-rw-r--r--lib/VNWeb/Discussions/PostEdit.pm2
-rw-r--r--lib/VNWeb/Discussions/Thread.pm4
-rw-r--r--lib/VNWeb/Discussions/UPosts.pm2
-rw-r--r--lib/VNWeb/Docs/Edit.pm14
-rw-r--r--lib/VNWeb/Docs/Lib.pm4
-rw-r--r--lib/VNWeb/Docs/Page.pm8
-rw-r--r--lib/VNWeb/Elm.pm20
-rw-r--r--lib/VNWeb/Graph.pm3
-rw-r--r--lib/VNWeb/HTML.pm68
-rw-r--r--lib/VNWeb/Images/Lib.pm2
-rw-r--r--lib/VNWeb/Images/List.pm14
-rw-r--r--lib/VNWeb/Images/Vote.pm2
-rw-r--r--lib/VNWeb/Misc/Feeds.pm6
-rw-r--r--lib/VNWeb/Misc/History.pm51
-rw-r--r--lib/VNWeb/Misc/HomePage.pm10
-rw-r--r--lib/VNWeb/Misc/Redirects.pm8
-rw-r--r--lib/VNWeb/Misc/Reports.pm13
-rw-r--r--lib/VNWeb/Prelude.pm76
-rw-r--r--lib/VNWeb/Producers/Edit.pm28
-rw-r--r--lib/VNWeb/Producers/Graph.pm8
-rw-r--r--lib/VNWeb/Producers/List.pm2
-rw-r--r--lib/VNWeb/Producers/Page.pm20
-rw-r--r--lib/VNWeb/Releases/Edit.pm22
-rw-r--r--lib/VNWeb/Releases/Elm.pm2
-rw-r--r--lib/VNWeb/Releases/Lib.pm2
-rw-r--r--lib/VNWeb/Releases/Page.pm16
-rw-r--r--lib/VNWeb/Releases/VNTab.pm4
-rw-r--r--lib/VNWeb/Reviews/Edit.pm8
-rw-r--r--lib/VNWeb/Reviews/List.pm8
-rw-r--r--lib/VNWeb/Reviews/Page.pm10
-rw-r--r--lib/VNWeb/Reviews/VNTab.pm6
-rw-r--r--lib/VNWeb/Staff/Edit.pm16
-rw-r--r--lib/VNWeb/Staff/List.pm2
-rw-r--r--lib/VNWeb/Staff/Page.pm14
-rw-r--r--lib/VNWeb/TT/TagLinks.pm8
-rw-r--r--lib/VNWeb/ULists/Elm.pm36
-rw-r--r--lib/VNWeb/ULists/Export.pm6
-rw-r--r--lib/VNWeb/ULists/Lib.pm2
-rw-r--r--lib/VNWeb/ULists/List.pm14
-rw-r--r--lib/VNWeb/User/Edit.pm14
-rw-r--r--lib/VNWeb/User/List.pm12
-rw-r--r--lib/VNWeb/User/Login.pm2
-rw-r--r--lib/VNWeb/User/Notifications.pm20
-rw-r--r--lib/VNWeb/User/Page.pm22
-rw-r--r--lib/VNWeb/User/PassReset.pm2
-rw-r--r--lib/VNWeb/User/PassSet.pm2
-rw-r--r--lib/VNWeb/User/Register.pm2
-rw-r--r--lib/VNWeb/VN/Edit.pm38
-rw-r--r--lib/VNWeb/VN/Graph.pm10
-rw-r--r--lib/VNWeb/VN/List.pm4
-rw-r--r--lib/VNWeb/VN/Page.pm66
-rw-r--r--lib/VNWeb/VN/Tagmod.pm4
-rw-r--r--lib/VNWeb/VN/Votes.pm2
-rw-r--r--lib/VNWeb/Validation.pm6
-rw-r--r--sql/data.sql2
-rw-r--r--sql/func.sql191
-rw-r--r--sql/schema.sql158
-rw-r--r--sql/tableattrs.sql7
-rwxr-xr-xutil/dbdump.pl4
-rwxr-xr-xutil/devdump.pl66
-rwxr-xr-xutil/revision-integrity.pl4
-rwxr-xr-xutil/saved-queries.pl12
-rwxr-xr-xutil/sqleditfunc.pl34
-rw-r--r--util/updates/2021-03-01-entries-to-vndbid.sql245
131 files changed, 1244 insertions, 1011 deletions
diff --git a/css/skins/air.sass b/css/skins/air.sass
index d1d89f92..09f2d376 100644
--- a/css/skins/air.sass
+++ b/css/skins/air.sass
@@ -1,4 +1,4 @@
-// userid: 13885 name: AIR (sky blue)
+// userid: u13885 name: AIR (sky blue)
////////////////////////////////////////////////////////////////
// 'AIR' skin for VNDB.org //
diff --git a/css/skins/angel.sass b/css/skins/angel.sass
index 4444291f..07246106 100644
--- a/css/skins/angel.sass
+++ b/css/skins/angel.sass
@@ -1,4 +1,4 @@
-// userid: 2 name: Angelic Serenade (dark blue)
+// userid: u2 name: Angelic Serenade (dark blue)
// ^ Must be the first line of skin files, read by VNDB::Skins.
// text
diff --git a/css/skins/aselia_01.sass b/css/skins/aselia_01.sass
index 6400e607..ee2f242b 100644
--- a/css/skins/aselia_01.sass
+++ b/css/skins/aselia_01.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Eien no Aselia (falu red)
+// userid: u51 name: Eien no Aselia (falu red)
// Eien no Aselia skin made using Minitokyo.Eien.no.Aselia.Scans_373967
// created: 09/27/2009 by echomateria
diff --git a/css/skins/carnevale.sass b/css/skins/carnevale.sass
index ab89f89f..bbee23a8 100644
--- a/css/skins/carnevale.sass
+++ b/css/skins/carnevale.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Gekkou no Carnevale (black)
+// userid: u51 name: Gekkou no Carnevale (black)
// Gekkou no Carnevale skin made using a wallpaper comes with the game
// created: 22/01/2009 by echomateria
diff --git a/css/skins/eiel.sass b/css/skins/eiel.sass
index 1e844194..b9d18030 100644
--- a/css/skins/eiel.sass
+++ b/css/skins/eiel.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Jingai Makyo (peach-orange)
+// userid: u51 name: Jingai Makyo (peach-orange)
// A skin made using an image I had for a long time without knowing it's source,
// thankfully this skin finally brought out the answer that it was from Jingai Makyo.
diff --git a/css/skins/ever17_01.sass b/css/skins/ever17_01.sass
index 56766614..278e9383 100644
--- a/css/skins/ever17_01.sass
+++ b/css/skins/ever17_01.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Ever17 (bondi blue)
+// userid: u51 name: Ever17 (bondi blue)
// Ever 17 skin made using the images from the extras section of the game
// created: 01/01/2009 by echomateria
diff --git a/css/skins/fate_01.sass b/css/skins/fate_01.sass
index 37d49c0d..ca5551bc 100644
--- a/css/skins/fate_01.sass
+++ b/css/skins/fate_01.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Fate/stay night (seal brown)
+// userid: u51 name: Fate/stay night (seal brown)
// FSN skin skin made using a popular fanart
// created: 12/31/2008 by echomateria
diff --git a/css/skins/fate_02.sass b/css/skins/fate_02.sass
index 6cf01f25..872baec5 100644
--- a/css/skins/fate_02.sass
+++ b/css/skins/fate_02.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Fate/stay night (pale carmine)
+// userid: u51 name: Fate/stay night (pale carmine)
// FSN skin made using a popular fanart
// created: 01/01/2009 by echomateria
diff --git a/css/skins/grey.sass b/css/skins/grey.sass
index d85f16dd..3655dec3 100644
--- a/css/skins/grey.sass
+++ b/css/skins/grey.sass
@@ -1,4 +1,4 @@
-// userid: 2 name: Touhou (grey)
+// userid: u2 name: Touhou (grey)
$maintext: #222
$grayedout: #666
diff --git a/css/skins/higanbana.sass b/css/skins/higanbana.sass
index 978c56d0..3074e2f7 100644
--- a/css/skins/higanbana.sass
+++ b/css/skins/higanbana.sass
@@ -1,4 +1,4 @@
-// userid: 13885 name: Higanbana no Saku Yoru ni (maroon)
+// userid: u13885 name: Higanbana no Saku Yoru ni (maroon)
////////////////////////////////////////////////////////////////
// 'Higanbana no Saku Yoru ni' skin for VNDB.org //
diff --git a/css/skins/higu.sass b/css/skins/higu.sass
index ebf606f2..dd04a2fb 100644
--- a/css/skins/higu.sass
+++ b/css/skins/higu.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Higurashi no Naku Koro ni (orange)
+// userid: u51 name: Higurashi no Naku Koro ni (orange)
// Higurashi no Naku Koro ni skin made using an image I found in MiniTokyo
// created: 22/01/2009 by echomateria
diff --git a/css/skins/lb.sass b/css/skins/lb.sass
index 6f7a3316..3dcd86a4 100644
--- a/css/skins/lb.sass
+++ b/css/skins/lb.sass
@@ -1,4 +1,4 @@
-// userid: 93 name: Little Busters! (pink)
+// userid: u93 name: Little Busters! (pink)
$maintext: #408
$grayedout: #670159
diff --git a/css/skins/lb_02.sass b/css/skins/lb_02.sass
index bb80d0f6..acd5b5de 100644
--- a/css/skins/lb_02.sass
+++ b/css/skins/lb_02.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Little Busters! (lemon chiffon)
+// userid: u51 name: Little Busters! (lemon chiffon)
// Little Busters! skin made using the Minitokyo.Little.Busters.Scans_316439
// created: 09/27/2009 by echomateria
diff --git a/css/skins/primitive.sass b/css/skins/primitive.sass
index 44ae6672..53e4b842 100644
--- a/css/skins/primitive.sass
+++ b/css/skins/primitive.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Primitive Link (pale chestnut)
+// userid: u51 name: Primitive Link (pale chestnut)
// Primitive Link skin made using an image that I liked without knowing what it's based on for a long time
// created: 23/01/2009 by echomateria
diff --git a/css/skins/saya.sass b/css/skins/saya.sass
index eeec4c9d..61be9661 100644
--- a/css/skins/saya.sass
+++ b/css/skins/saya.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Saya no Uta (dark scarlet)
+// userid: u51 name: Saya no Uta (dark scarlet)
// Saya no Uta skin made using a criminally cute fanart
// created: 22/01/2009 by echomateria
diff --git a/css/skins/seinarukana.sass b/css/skins/seinarukana.sass
index 77cdfee0..6c5a270b 100644
--- a/css/skins/seinarukana.sass
+++ b/css/skins/seinarukana.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Seinarukana (white)
+// userid: u51 name: Seinarukana (white)
// Seinarukana skin made using a callendar image
// created: 12/31/2008 by echomateria
diff --git a/css/skins/taka.sass b/css/skins/taka.sass
index 1569c586..07cb00f7 100644
--- a/css/skins/taka.sass
+++ b/css/skins/taka.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Sora no Iro, Mizu no Iro (turquoise)
+// userid: u51 name: Sora no Iro, Mizu no Iro (turquoise)
// A Sora no Iro, Mizu no Iro skin based on a wallpaper named My Perfect Day
// created: 23/01/2009 by echomateria
diff --git a/css/skins/teal.sass b/css/skins/teal.sass
index 7ac70ce9..af2fd02b 100644
--- a/css/skins/teal.sass
+++ b/css/skins/teal.sass
@@ -1,4 +1,4 @@
-// userid: 163596 name: Teal (teal)
+// userid: u163596 name: Teal (teal)
// by sw1tchbl4d3
$maintext: #ddd
diff --git a/css/skins/term.sass b/css/skins/term.sass
index 90cf678f..49f795c2 100644
--- a/css/skins/term.sass
+++ b/css/skins/term.sass
@@ -1,4 +1,4 @@
-// userid: 93 name: Neon (black)
+// userid: u93 name: Neon (black)
$maintext: #0f0
$grayedout: #aaa
diff --git a/css/skins/tsukihime.sass b/css/skins/tsukihime.sass
index e50c3bf3..64b45591 100644
--- a/css/skins/tsukihime.sass
+++ b/css/skins/tsukihime.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Tsukihime (midnight blue)
+// userid: u51 name: Tsukihime (midnight blue)
// Tsukihime skin made using an image from the Tsukihime Plus+Disc
// created: 02/01/2009 by echomateria
diff --git a/css/skins/tsukihime_02.sass b/css/skins/tsukihime_02.sass
index df872e07..e895055a 100644
--- a/css/skins/tsukihime_02.sass
+++ b/css/skins/tsukihime_02.sass
@@ -1,4 +1,4 @@
-// userid: 51 name: Tsukihime (black)
+// userid: u51 name: Tsukihime (black)
// Tsukihime skin made with an awesome Akiha artwork from Tsukihime PLUS disc
// created: 23/01/2009 by echomateria
diff --git a/elm/AdvSearch/Fields.elm b/elm/AdvSearch/Fields.elm
index 81a6d6b1..1e80b45b 100644
--- a/elm/AdvSearch/Fields.elm
+++ b/elm/AdvSearch/Fields.elm
@@ -640,7 +640,7 @@ fieldToQuery dat (_, _, model) =
FMAniEro m -> AS.toQuery (QInt 13) m
FMAniStory m -> AS.toQuery (QInt 14) m
FMRType m -> AS.toQuery (QStr 16) m
- FMLabel m -> AS.toQuery (\op v -> QTuple 12 op (Maybe.withDefault 0 dat.uid) v) m
+ FMLabel m -> AS.toQuery (\op v -> QTuple 12 op (Maybe.withDefault 0 (Maybe.map vndbidNum dat.uid)) v) m
FMRList m -> AS.toQuery (QInt 18) m
FMSRole m -> AS.toQuery (QStr 5) m
FMHeight m -> AR.toQuery (QInt 6) (QStr 6) m
diff --git a/elm/AdvSearch/Lib.elm b/elm/AdvSearch/Lib.elm
index 51aa2882..46f84e0b 100644
--- a/elm/AdvSearch/Lib.elm
+++ b/elm/AdvSearch/Lib.elm
@@ -173,11 +173,11 @@ type alias Data =
{ objid : Int -- Incremental integer for global identifiers
, level : Int -- Nesting level of the field being processed
, parentTypes : Set.Set String -- Only used for 'view' functions: query types that the current field is a subquery of
- , uid : Maybe Int
+ , uid : Maybe String
, labels : List (Int, String)
, defaultSpoil : Int
- , producers : Dict.Dict Int GApi.ApiProducerResult
- , staff : Dict.Dict Int GApi.ApiStaffResult
+ , producers : Dict.Dict String GApi.ApiProducerResult
+ , staff : Dict.Dict String GApi.ApiStaffResult
, tags : Dict.Dict Int GApi.ApiTagResult
, traits : Dict.Dict Int GApi.ApiTraitResult
, anime : Dict.Dict Int GApi.ApiAnimeResult
diff --git a/elm/AdvSearch/Main.elm b/elm/AdvSearch/Main.elm
index 5f4d6406..06f60e4d 100644
--- a/elm/AdvSearch/Main.elm
+++ b/elm/AdvSearch/Main.elm
@@ -33,7 +33,7 @@ main = Browser.element
type alias SQuery = { name: String, query: String }
type alias Recv =
- { uid : Maybe Int
+ { uid : Maybe String
, labels : List { id: Int, label: String }
, defaultSpoil : Int
, saved : List SQuery
diff --git a/elm/AdvSearch/Producers.elm b/elm/AdvSearch/Producers.elm
index 2144b955..0beeab46 100644
--- a/elm/AdvSearch/Producers.elm
+++ b/elm/AdvSearch/Producers.elm
@@ -44,9 +44,9 @@ update dat msg model =
in case res of
Nothing -> (dat, { model | search = nm }, c)
Just p ->
- if Set.member p.id model.sel.sel then (dat, { model | search = nm }, c)
+ if Set.member (vndbidNum p.id) model.sel.sel then (dat, { model | search = nm }, c)
else ( { dat | producers = Dict.insert p.id p dat.producers }
- , { model | search = A.clear nm "", sel = S.update (S.Sel p.id True) model.sel }
+ , { model | search = A.clear nm "", sel = S.update (S.Sel (vndbidNum p.id) True) model.sel }
, c )
@@ -76,7 +76,7 @@ view prod dat model =
[s] -> span [ class "nowrap" ]
[ S.lblPrefix model.sel
, b [ class "grayedout" ] [ text <| "p" ++ String.fromInt s ++ ":" ]
- , Dict.get s dat.producers |> Maybe.map (\p -> p.name) |> Maybe.withDefault "" |> text
+ , Dict.get (vndbid 'p' s) dat.producers |> Maybe.map (\p -> p.name) |> Maybe.withDefault "" |> text
]
l -> span [] [ S.lblPrefix model.sel, text <| lbl ++ " (" ++ String.fromInt (List.length l) ++ ")" ]
, \() ->
@@ -88,7 +88,7 @@ view prod dat model =
li [ style "overflow" "hidden", style "text-overflow" "ellipsis" ]
[ inputButton "X" (Sel (S.Sel s False)) []
, b [ class "grayedout" ] [ text <| " p" ++ String.fromInt s ++ ": " ]
- , Dict.get s dat.producers |> Maybe.map (\p -> a [ href ("/p" ++ String.fromInt p.id), target "_blank", style "display" "inline" ] [ text p.name ]) |> Maybe.withDefault (text "")
+ , Dict.get (vndbid 'p' s) dat.producers |> Maybe.map (\p -> a [ href ("/" ++ p.id), target "_blank", style "display" "inline" ] [ text p.name ]) |> Maybe.withDefault (text "")
]
) (Set.toList model.sel.sel)
, A.view model.conf model.search [ placeholder "Search..." ]
diff --git a/elm/AdvSearch/Set.elm b/elm/AdvSearch/Set.elm
index a60f24df..6a1b6003 100644
--- a/elm/AdvSearch/Set.elm
+++ b/elm/AdvSearch/Set.elm
@@ -411,7 +411,7 @@ labelView dat model =
labelFromQuery dat q =
fromQuery (\qs ->
case qs of
- QTuple 12 op uid l -> if Just uid == dat.uid then Just (op, l) else Nothing
+ QTuple 12 op uid l -> if Just (vndbid 'u' uid) == dat.uid then Just (op, l) else Nothing
_ -> Nothing) dat q
diff --git a/elm/AdvSearch/Staff.elm b/elm/AdvSearch/Staff.elm
index 97d6a577..d2060f8d 100644
--- a/elm/AdvSearch/Staff.elm
+++ b/elm/AdvSearch/Staff.elm
@@ -44,9 +44,9 @@ update dat msg model =
in case res of
Nothing -> (dat, { model | search = nm }, c)
Just s ->
- if Set.member s.id model.sel.sel then (dat, { model | search = nm }, c)
+ if Set.member (vndbidNum s.id) model.sel.sel then (dat, { model | search = nm }, c)
else ( { dat | staff = Dict.insert s.id s dat.staff }
- , { model | search = A.clear nm "", sel = S.update (S.Sel s.id True) model.sel }
+ , { model | search = A.clear nm "", sel = S.update (S.Sel (vndbidNum s.id) True) model.sel }
, c )
@@ -73,7 +73,7 @@ view dat model =
[s] -> span [ class "nowrap" ]
[ S.lblPrefix model.sel
, b [ class "grayedout" ] [ text <| "s" ++ String.fromInt s ++ ":" ]
- , Dict.get s dat.staff |> Maybe.map (\e -> e.name) |> Maybe.withDefault "" |> text
+ , Dict.get (vndbid 's' s) dat.staff |> Maybe.map (\e -> e.name) |> Maybe.withDefault "" |> text
]
l -> span [] [ S.lblPrefix model.sel, text <| "Names (" ++ String.fromInt (List.length l) ++ ")" ]
, \() ->
@@ -85,7 +85,7 @@ view dat model =
li [ style "overflow" "hidden", style "text-overflow" "ellipsis" ]
[ inputButton "X" (Sel (S.Sel s False)) []
, b [ class "grayedout" ] [ text <| " s" ++ String.fromInt s ++ ": " ]
- , Dict.get s dat.staff |> Maybe.map (\e -> a [ href ("/s" ++ String.fromInt e.id), target "_blank", style "display" "inline" ] [ text e.name ]) |> Maybe.withDefault (text "")
+ , Dict.get (vndbid 's' s) dat.staff |> Maybe.map (\e -> a [ href ("/" ++ e.id), target "_blank", style "display" "inline" ] [ text e.name ]) |> Maybe.withDefault (text "")
]
) (Set.toList model.sel.sel)
, A.view model.conf model.search [ placeholder "Search..." ]
diff --git a/elm/CharEdit.elm b/elm/CharEdit.elm
index 95011c88..c2de581e 100644
--- a/elm/CharEdit.elm
+++ b/elm/CharEdit.elm
@@ -64,7 +64,7 @@ type alias Model =
, weight : Maybe Int
, bloodt : String
, cupSize : String
- , main : Maybe Int
+ , main : Maybe String
, mainRef : Bool
, mainHas : Bool
, mainName : String
@@ -77,8 +77,8 @@ type alias Model =
, traitSelSpl : Int
, vns : List GCE.RecvVns
, vnSearch : A.Model GApi.ApiVNResult
- , releases : Dict.Dict Int (List GCE.RecvReleasesRels) -- vid -> list of releases
- , id : Maybe Int
+ , releases : Dict.Dict String (List GCE.RecvReleasesRels) -- vid -> list of releases
+ , id : Maybe String
}
@@ -194,13 +194,13 @@ type Msg
| TraitSel Int Int
| TraitSpoil Int Int
| TraitSearch (A.Msg GApi.ApiTraitResult)
- | VnRel Int (Maybe Int)
+ | VnRel Int (Maybe String)
| VnRole Int String
| VnSpoil Int Int
| VnDel Int
- | VnRelAdd Int String
+ | VnRelAdd String String
| VnSearch (A.Msg GApi.ApiVNResult)
- | VnRelGet Int GApi.Response
+ | VnRelGet String GApi.Response
update : Msg -> Model -> (Model, Cmd Msg)
@@ -283,7 +283,7 @@ update msg model =
isValid : Model -> Bool
isValid model = not
( (model.name /= "" && model.name == model.original)
- || hasDuplicates (List.map (\v -> (v.vid, Maybe.withDefault 0 v.rid)) model.vns)
+ || hasDuplicates (List.map (\v -> (v.vid, Maybe.withDefault "" v.rid)) model.vns)
|| not (Img.isValid model.image)
|| (model.mainHas && model.main /= Nothing && model.main == model.id)
)
@@ -369,8 +369,8 @@ view model =
, br_ 2
, Maybe.withDefault (text "No character selected") <| Maybe.map (\m -> span []
[ text "Selected character: "
- , b [ class "grayedout" ] [ text <| "c" ++ String.fromInt m ++ ": " ]
- , a [ href <| "/c" ++ String.fromInt m ] [ text model.mainName ]
+ , b [ class "grayedout" ] [ text <| m ++ ": " ]
+ , a [ href <| "/" ++ m ] [ text model.mainName ]
, if Just m == model.id then b [ class "standout" ] [ br [] [], text "A character can't be an instance of itself. Please select another character or disable the above checkbox to remove the instance." ] else text ""
]) model.main
, br [] []
@@ -446,24 +446,24 @@ view model =
case lst of
(x::xs) -> if Set.member x set then uniq xs set else x :: uniq xs (Set.insert x set)
[] -> []
- showrel r = "[" ++ (RDate.format (RDate.expand r.released)) ++ " " ++ (String.join "," r.lang) ++ "] " ++ r.title ++ " (r" ++ String.fromInt r.id ++ ")"
+ showrel r = "[" ++ (RDate.format (RDate.expand r.released)) ++ " " ++ (String.join "," r.lang) ++ "] " ++ r.title ++ " (" ++ r.id ++ ")"
vn vid lst rels =
let title = Maybe.withDefault "<unknown>" <| Maybe.map (\(_,v) -> v.title) <| List.head lst
in
- [ ( String.fromInt vid
+ [ ( vid
, tr [ class "newpart" ] [ td [ colspan 4, style "padding-bottom" "5px" ]
- [ b [ class "grayedout" ] [ text <| "v" ++ String.fromInt vid ++ ":" ]
- , a [ href <| "/v" ++ String.fromInt vid ] [ text title ]
+ [ b [ class "grayedout" ] [ text <| vid ++ ":" ]
+ , a [ href <| "/" ++ vid ] [ text title ]
]]
)
] ++ List.map (\(idx,item) ->
- ( String.fromInt vid ++ "i" ++ String.fromInt (Maybe.withDefault 0 item.rid)
+ ( vid ++ "i" ++ Maybe.withDefault "r0" item.rid
, tr []
[ td [] [ inputSelect "" item.rid (VnRel idx) [ style "width" "400px", style "margin" "0 15px" ] <|
(Nothing, if List.length lst == 1 then "All (full) releases" else "Other releases")
:: List.map (\r -> (Just r.id, showrel r)) rels
++ if isJust item.rid && List.isEmpty (List.filter (\r -> Just r.id == item.rid) rels)
- then [(item.rid, "Deleted release: r" ++ String.fromInt (Maybe.withDefault 0 item.rid))] else []
+ then [(item.rid, "Deleted release: " ++ Maybe.withDefault "" item.rid)] else []
]
, td [] [ inputSelect "" item.role (VnRole idx) [] GT.charRoles ]
, td [] [ inputSelect "" item.spoil (VnSpoil idx) [ style "width" "130px", style "margin" "0 5px" ] spoilOpts ]
@@ -471,13 +471,13 @@ view model =
]
)
) lst
- ++ (if List.map (\(_,r) -> Maybe.withDefault 0 r.rid) lst |> hasDuplicates |> not then [] else [
- ( String.fromInt vid ++ "dup"
+ ++ (if List.map (\(_,r) -> Maybe.withDefault "" r.rid) lst |> hasDuplicates |> not then [] else [
+ ( vid ++ "dup"
, td [] [ td [ colspan 4, style "padding" "0 15px" ] [ b [ class "standout" ] [ text "List contains duplicate releases." ] ] ]
)
])
++ (if 1 /= List.length (List.filter (\(_,r) -> isJust r.rid) lst) then [] else [
- ( String.fromInt vid ++ "warn"
+ ( vid ++ "warn"
, tr [] [ td [ colspan 4, style "padding" "0 15px" ]
[ b [ class "standout" ] [ text "Note: " ]
, text "Only select specific releases if the character has a significantly different role in those releases. "
@@ -486,7 +486,7 @@ view model =
])
])
++ (if List.length lst > List.length rels then [] else [
- ( String.fromInt vid ++ "add"
+ ( vid ++ "add"
, tr [] [ td [ colspan 4 ] [ inputButton "add release" (VnRelAdd vid title) [style "margin" "0 15px"] ] ]
)
])
diff --git a/elm/Discussions/Edit.elm b/elm/Discussions/Edit.elm
index 082b4634..d478f52b 100644
--- a/elm/Discussions/Edit.elm
+++ b/elm/Discussions/Edit.elm
@@ -87,7 +87,7 @@ numPollOptions : Model -> Int
numPollOptions model = Maybe.withDefault 0 (Maybe.map (\o -> List.length o.options) model.poll)
dupBoards : Model -> Bool
-dupBoards model = hasDuplicates (List.map (\b -> (b.btype, b.iid)) (Maybe.withDefault [] model.boards))
+dupBoards model = hasDuplicates (List.map (\b -> (b.btype, Maybe.withDefault "" b.iid)) (Maybe.withDefault [] model.boards))
isValid : Model -> Bool
isValid model = not (model.boards == Just [] || dupBoards model || Maybe.map (\p -> p.max_options < 1 || p.max_options > numPollOptions model) model.poll == Just True)
@@ -151,13 +151,13 @@ view model =
, a [ href "#", onClickD (BoardDel n), tabindex 10 ] [ text "remove" ]
, text "] "
, text (Maybe.withDefault "" (lookup bd.btype boardTypes))
- ] ++ case (bd.btype, bd.title) of
- (_, Just title) ->
+ ] ++ case (bd.btype, bd.iid, bd.title) of
+ (_, Just iid, Just title) ->
[ b [ class "grayedout" ] [ text " > " ]
- , a [ href <| "/" ++ bd.btype ++ String.fromInt bd.iid ] [ text title ]
+ , a [ href <| "/" ++ iid ] [ text title ]
]
- ("u", _) -> [ b [ class "grayedout" ] [ text " > " ], text <| bd.btype ++ String.fromInt bd.iid ++ " (deleted)" ]
- (_, _) -> []
+ ("u", Just iid, _) -> [ b [ class "grayedout" ] [ text " > " ], text <| iid ++ " (deleted)" ]
+ _ -> []
boards () =
[ text "You can link this thread to multiple boards. Every visual novel, producer and user in the database has its own board,"
diff --git a/elm/DocEdit.elm b/elm/DocEdit.elm
index df2b333e..b5b52c2d 100644
--- a/elm/DocEdit.elm
+++ b/elm/DocEdit.elm
@@ -28,7 +28,7 @@ type alias Model =
, editsum : Editsum.Model
, title : String
, content : TP.Model
- , id : Int
+ , id : String
}
@@ -77,7 +77,7 @@ view : Model -> Html Msg
view model =
form_ "" Submit (model.state == Api.Loading)
[ div [ class "mainbox" ]
- [ h1 [] [ text <| "Edit d" ++ String.fromInt model.id ]
+ [ h1 [] [ text <| "Edit " ++ model.id ]
, table [ class "formtable" ]
[ formField "title::Title" [ inputText "title" model.title Title (style "width" "300px" :: GD.valTitle) ]
, formField "none"
diff --git a/elm/ImageFlagging.elm b/elm/ImageFlagging.elm
index 275f90ec..b2f73352 100644
--- a/elm/ImageFlagging.elm
+++ b/elm/ImageFlagging.elm
@@ -232,7 +232,7 @@ view model =
[ td [ Ffi.innerHtml v.user ] []
, td [] [ text <| if v.sexual == 0 then "Safe" else if v.sexual == 1 then "Suggestive" else "Explicit" ]
, td [] [ text <| if v.violence == 0 then "Tame" else if v.violence == 1 then "Violent" else "Brutal" ]
- , td [] <| Maybe.withDefault [] <| Maybe.map (\u -> [ a [ href <| "/img/list?view=" ++ model.nsfwToken ++ "&u=" ++ String.fromInt u ] [ text "votes" ] ]) v.uid
+ , td [] <| Maybe.withDefault [] <| Maybe.map (\u -> [ a [ href <| "/img/list?view=" ++ model.nsfwToken ++ "&u=" ++ u ] [ text "votes" ] ]) v.uid
]
) i.votes
]
diff --git a/elm/Lib/Autocomplete.elm b/elm/Lib/Autocomplete.elm
index 45a67fa1..61f13caf 100644
--- a/elm/Lib/Autocomplete.elm
+++ b/elm/Lib/Autocomplete.elm
@@ -90,7 +90,7 @@ boardSource =
Just title -> [ b [ class "grayedout" ] [ text " > " ], text title ]
_ -> []
)
- , key = \i -> i.btype ++ String.fromInt i.iid
+ , key = \i -> Maybe.withDefault i.btype i.iid
}
@@ -139,9 +139,9 @@ vnSource =
GApi.VNResult e -> Just e
_ -> Nothing
, view = \i ->
- [ b [ class "grayedout" ] [ text <| "v" ++ String.fromInt i.id ++ ": " ]
+ [ b [ class "grayedout" ] [ text <| i.id ++ ": " ]
, text i.title ]
- , key = \i -> String.fromInt i.id
+ , key = \i -> i.id
}
@@ -152,9 +152,9 @@ producerSource =
GApi.ProducerResult e -> Just e
_ -> Nothing
, view = \i ->
- [ b [ class "grayedout" ] [ text <| "p" ++ String.fromInt i.id ++ ": " ]
+ [ b [ class "grayedout" ] [ text <| i.id ++ ": " ]
, text i.name ]
- , key = \i -> String.fromInt i.id
+ , key = \i -> i.id
}
@@ -165,7 +165,7 @@ staffSource =
GApi.StaffResult e -> Just e
_ -> Nothing
, view = \i ->
- [ b [ class "grayedout" ] [ text <| "s" ++ String.fromInt i.id ++ ": " ]
+ [ b [ class "grayedout" ] [ text <| i.id ++ ": " ]
, text i.name ]
, key = \i -> String.fromInt i.aid
}
@@ -178,13 +178,13 @@ charSource =
GApi.CharResult e -> Just e
_ -> Nothing
, view = \i ->
- [ b [ class "grayedout" ] [ text <| "c" ++ String.fromInt i.id ++ ": " ]
+ [ b [ class "grayedout" ] [ text <| i.id ++ ": " ]
, text i.name
, Maybe.withDefault (text "") <| Maybe.map (\m ->
- b [ class "grayedout" ] [ text <| " (instance of c" ++ String.fromInt m.id ++ ": " ++ m.name ]
+ b [ class "grayedout" ] [ text <| " (instance of " ++ m.id ++ ": " ++ m.name ]
) i.main
]
- , key = \i -> String.fromInt i.id
+ , key = \i -> i.id
}
diff --git a/elm/Lib/Util.elm b/elm/Lib/Util.elm
index ba0a8a54..2ab174f9 100644
--- a/elm/Lib/Util.elm
+++ b/elm/Lib/Util.elm
@@ -68,6 +68,13 @@ imageUrl id =
in Ffi.urlStatic ++ "/" ++ String.left 2 id ++ "/" ++ String.fromInt (modBy 10 (num // 10)) ++ String.fromInt (modBy 10 num) ++ "/" ++ String.fromInt num ++ ".jpg"
+vndbidNum : String -> Int
+vndbidNum = String.dropLeft 1 >> String.toInt >> Maybe.withDefault 0
+
+
+vndbid : Char -> Int -> String
+vndbid c n = String.fromChar c ++ String.fromInt n
+
jap_ : Regex.Regex
jap_ = Maybe.withDefault Regex.never (Regex.fromString "[\\u3000-\\u9fff\\uff00-\\uff9f]")
diff --git a/elm/ProducerEdit.elm b/elm/ProducerEdit.elm
index 213f8516..b17e56d1 100644
--- a/elm/ProducerEdit.elm
+++ b/elm/ProducerEdit.elm
@@ -38,7 +38,7 @@ type alias Model =
, desc : TP.Model
, rel : List GPE.RecvRelations
, relSearch : A.Model GApi.ApiProducerResult
- , id : Maybe Int
+ , id : Maybe String
, dupCheck : Bool
, dupProds : List GApi.ApiProducerResult
}
@@ -185,8 +185,8 @@ view model =
, formField "Related producers"
[ if List.isEmpty model.rel then text ""
else table [] <| List.indexedMap (\i p -> tr []
- [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| "p" ++ String.fromInt p.pid ++ ":" ] ]
- , td [ style "text-align" "right"] [ a [ href <| "/p" ++ String.fromInt p.pid ] [ text p.name ] ]
+ [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| p.pid ++ ":" ] ]
+ , td [ style "text-align" "right"] [ a [ href <| "/" ++ p.pid ] [ text p.name ] ]
, td []
[ text "is an "
, inputSelect "" p.relation (RelRel i) [] GT.producerRelations
@@ -210,7 +210,7 @@ view model =
, text "Please check this list to avoid creating a duplicate producer entry. "
, text "Be especially wary of items that have been deleted! To see why an entry has been deleted, click on its title."
, ul [] <| List.map (\p -> li []
- [ a [ href <| "/p" ++ String.fromInt p.id ] [ text p.name ]
+ [ a [ href <| "/" ++ p.id ] [ text p.name ]
, if p.hidden then b [ class "standout" ] [ text " (deleted)" ] else text ""
]
) model.dupProds
diff --git a/elm/ReleaseEdit.elm b/elm/ReleaseEdit.elm
index 78fda8ca..280a12cb 100644
--- a/elm/ReleaseEdit.elm
+++ b/elm/ReleaseEdit.elm
@@ -65,7 +65,7 @@ type alias Model =
, prodAdd : A.Model GApi.ApiProducerResult
, notes : TP.Model
, editsum : Editsum.Model
- , id : Maybe Int
+ , id : Maybe String
}
@@ -368,8 +368,8 @@ viewGen model =
, formField "Visual novels"
[ if List.isEmpty model.vn then b [ class "standout" ] [ text "No visual novels selected.", br [] [] ]
else table [] <| List.indexedMap (\i v -> tr []
- [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| "v" ++ String.fromInt v.vid ++ ":" ] ]
- , td [] [ a [ href <| "/v" ++ String.fromInt v.vid ] [ text v.title ] ]
+ [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| v.vid ++ ":" ] ]
+ , td [] [ a [ href <| "/" ++ v.vid ] [ text v.title ] ]
, td [] [ inputButton "remove" (VNDel i) [] ]
]
) model.vn
@@ -378,8 +378,8 @@ viewGen model =
, tr [ class "newpart" ] [ td [ colspan 2 ] [] ]
, formField "Producers"
[ table [ class "compact" ] <| List.indexedMap (\i p -> tr []
- [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| "p" ++ String.fromInt p.pid ++ ":" ] ]
- , td [] [ a [ href <| "/p" ++ String.fromInt p.pid ] [ text p.name ] ]
+ [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| p.pid ++ ":" ] ]
+ , td [] [ a [ href <| "/" ++ p.pid ] [ text p.name ] ]
, td [] [ inputSelect "" (p.developer, p.publisher) (ProdRole i) [style "width" "100px"] [((True,False), "Developer"), ((False,True), "Publisher"), ((True,True), "Both")] ]
, td [] [ inputButton "remove" (ProdDel i) [] ]
]
diff --git a/elm/Reviews/Edit.elm b/elm/Reviews/Edit.elm
index c5314e27..a2ee425f 100644
--- a/elm/Reviews/Edit.elm
+++ b/elm/Reviews/Edit.elm
@@ -26,9 +26,9 @@ main = Browser.element
type alias Model =
{ state : Api.State
, id : Maybe String
- , vid : Int
+ , vid : String
, vntitle : String
- , rid : Maybe Int
+ , rid : Maybe String
, spoiler : Bool
, locked : Bool
, isfull : Bool
@@ -71,7 +71,7 @@ encode m =
type Msg
- = Release (Maybe Int)
+ = Release (Maybe String)
| Full Bool
| Spoiler Bool
| Locked Bool
@@ -98,11 +98,11 @@ update msg model =
Delete b -> ({ model | delete = b }, Cmd.none)
DoDelete -> ({ model | delState = Api.Loading }, GRD.send ({ id = Maybe.withDefault "" model.id }) Deleted)
- Deleted GApi.Success -> (model, load <| "/v" ++ String.fromInt model.vid)
+ Deleted GApi.Success -> (model, load <| "/" ++ model.vid)
Deleted r -> ({ model | delState = Api.Error r }, Cmd.none)
-showrel r = "[" ++ (RDate.format (RDate.expand r.released)) ++ " " ++ (String.join "," r.lang) ++ "] " ++ r.title ++ " (r" ++ String.fromInt r.id ++ ")"
+showrel r = "[" ++ (RDate.format (RDate.expand r.released)) ++ " " ++ (String.join "," r.lang) ++ "] " ++ r.title ++ " (" ++ r.id ++ ")"
view : Model -> Html Msg
view model =
@@ -125,12 +125,12 @@ view model =
]
, div [ class "mainbox" ]
[ table [ class "formtable" ]
- [ formField "Subject" [ a [ href <| "/v"++String.fromInt model.vid ] [ text model.vntitle ] ]
+ [ formField "Subject" [ a [ href <| "/"++model.vid ] [ text model.vntitle ] ]
, formField ""
[ inputSelect "" model.rid Release [style "width" "500px" ] <|
(Nothing, "No release selected")
:: List.map (\r -> (Just r.id, showrel r)) model.releases
- ++ if model.rid == Nothing || List.any (\r -> Just r.id == model.rid) model.releases then [] else [(model.rid, "Deleted or moved release: r"++Maybe.withDefault "" (Maybe.map String.fromInt model.rid))]
+ ++ if model.rid == Nothing || List.any (\r -> Just r.id == model.rid) model.releases then [] else [(model.rid, "Deleted or moved release: r"++Maybe.withDefault "" model.rid)]
, br [] []
, text "You do not have to select a release, but indicating which release your review is based on gives more context."
]
diff --git a/elm/StaffEdit.elm b/elm/StaffEdit.elm
index a2e4f5df..0256e69a 100644
--- a/elm/StaffEdit.elm
+++ b/elm/StaffEdit.elm
@@ -38,7 +38,7 @@ type alias Model =
, l_twitter : String
, l_anidb : Maybe Int
, l_pixiv : Int
- , id : Maybe Int
+ , id : Maybe String
}
diff --git a/elm/Tagmod.elm b/elm/Tagmod.elm
index 97ce93b0..c660a9aa 100644
--- a/elm/Tagmod.elm
+++ b/elm/Tagmod.elm
@@ -36,7 +36,7 @@ type Sel
type alias Model =
{ state : Api.State
, title : String
- , id : Int
+ , id : String
, mod : Bool
, tags : List Tag
, saved : List Tag
@@ -123,7 +123,7 @@ update msg model =
-viewTag : Tag -> Sel -> Int -> Bool -> Html Msg
+viewTag : Tag -> Sel -> String -> Bool -> Html Msg
viewTag t sel vid mod =
let
-- Similar to VNWeb::Tags::Lib::tagscore_
@@ -201,7 +201,7 @@ viewTag t sel vid mod =
, td [ class "tc_allspoil"] [ text <| Ffi.fmtFloat t.spoiler 2 ]
, td [ class "tc_allwho" ]
[ span [ style "opacity" <| if t.othnotes == "" then "0" else "1", style "cursor" "default", title t.othnotes ] [ text "💬 " ]
- , a [ href <| "/g/links?v="++String.fromInt vid++"&t="++String.fromInt t.id ] [ text "Who?" ]
+ , a [ href <| "/g/links?v="++vid++"&t="++String.fromInt t.id ] [ text "Who?" ]
]
]
diff --git a/elm/UList/LabelEdit.elm b/elm/UList/LabelEdit.elm
index 1011d950..d2877cf0 100644
--- a/elm/UList/LabelEdit.elm
+++ b/elm/UList/LabelEdit.elm
@@ -26,8 +26,8 @@ main = Browser.element
port ulistLabelChanged : Bool -> Cmd msg
type alias Model =
- { uid : Int
- , vid : Int
+ { uid : String
+ , vid : String
, labels : List GLE.RecvLabels
, sel : Set Int -- Set of label IDs applied on the server
, tsel : Set Int -- Set of label IDs applied on the client
@@ -43,7 +43,7 @@ init f =
, sel = Set.fromList f.selected
, tsel = Set.fromList f.selected
, state = Dict.empty
- , dd = DD.init ("ulist_labeledit_dd" ++ String.fromInt f.vid) Open
+ , dd = DD.init ("ulist_labeledit_dd" ++ f.vid) Open
}
type Msg
diff --git a/elm/UList/ManageLabels.elm b/elm/UList/ManageLabels.elm
index 61b7ebe3..2db1b68d 100644
--- a/elm/UList/ManageLabels.elm
+++ b/elm/UList/ManageLabels.elm
@@ -24,7 +24,7 @@ main = Browser.element
}
type alias Model =
- { uid : Int
+ { uid : String
, state : Api.State
, labels : List GML.SendLabels
, editing : Maybe Int
diff --git a/elm/UList/Opt.elm b/elm/UList/Opt.elm
index 87b123fa..9812a725 100644
--- a/elm/UList/Opt.elm
+++ b/elm/UList/Opt.elm
@@ -41,8 +41,8 @@ type alias Model =
, notesRev : Int
, notesState : Api.State
, rels : List RE.Model
- , relNfo : Dict Int GApi.ApiReleases
- , relOptions : Maybe (List (Int, String))
+ , relNfo : Dict String GApi.ApiReleases
+ , relOptions : Maybe (List (String, String))
, relState : Api.State
}
@@ -69,14 +69,14 @@ type Msg
| Notes String
| NotesSave Int
| NotesSaved Int GApi.Response
- | Rel Int RE.Msg
+ | Rel String RE.Msg
| RelLoad
| RelLoaded GApi.Response
- | RelAdd Int
+ | RelAdd String
showrel : GApi.ApiReleases -> String
-showrel r = "[" ++ (RDate.format (RDate.expand r.released)) ++ " " ++ (String.join "," r.lang) ++ "] " ++ r.title ++ " (r" ++ String.fromInt r.id ++ ")"
+showrel r = "[" ++ (RDate.format (RDate.expand r.released)) ++ " " ++ (String.join "," r.lang) ++ "] " ++ r.title ++ " (" ++ r.id ++ ")"
update : Msg -> Model -> (Model, Cmd Msg)
@@ -132,7 +132,7 @@ update msg model =
}, Cmd.none)
RelLoaded e -> ({ model | relState = Api.Error e }, Cmd.none)
RelAdd rid ->
- ( { model | rels = model.rels ++ (if rid == 0 then [] else [RE.init model.flags.vid { rid = rid, uid = model.flags.uid, status = Just 2, empty = "" }]) }
+ ( { model | rels = model.rels ++ (if rid == "" then [] else [RE.init model.flags.vid { rid = rid, uid = model.flags.uid, status = Just 2, empty = "" }]) }
, Task.perform (always <| Rel rid <| RE.Set (Just 2) True) <| Task.succeed True)
@@ -169,8 +169,8 @@ view model =
-- TODO: This <select> solution is ugly as hell, a Lib.DropDown-based solution would be nicer.
-- Or just throw all releases in the table and use the status field for add stuff.
case (model.relOptions, model.relState) of
- (Just opts, _) -> [ inputSelect "" 0 RelAdd [ style "width" "500px" ]
- <| (0, "-- add release --") :: List.filter (\(rid,_) -> not <| List.any (\r -> r.rid == rid) model.rels) opts ]
+ (Just opts, _) -> [ inputSelect "" "" RelAdd [ style "width" "500px" ]
+ <| ("", "-- add release --") :: List.filter (\(rid,_) -> not <| List.any (\r -> r.rid == rid) model.rels) opts ]
(_, Api.Normal) -> []
(_, Api.Loading) -> [ span [ class "spinner" ] [], text "Loading releases..." ]
(_, Api.Error e) -> [ b [ class "standout" ] [ text <| Api.showResponse e ], text ". ", a [ href "#", onClickD RelLoad ] [ text "Try again" ] ]
@@ -191,7 +191,7 @@ view model =
<| List.map platformIcon nfo.platforms
++ List.map langIcon nfo.lang
++ [ releaseTypeIcon nfo.rtype ]
- , td [ class "tco4" ] [ a [ href ("/r"++String.fromInt nfo.id), title nfo.original ] [ text nfo.title ] ]
+ , td [ class "tco4" ] [ a [ href ("/"++nfo.id), title nfo.original ] [ text nfo.title ] ]
]
confirm =
diff --git a/elm/UList/ReleaseEdit.elm b/elm/UList/ReleaseEdit.elm
index 5373e316..7f901d67 100644
--- a/elm/UList/ReleaseEdit.elm
+++ b/elm/UList/ReleaseEdit.elm
@@ -15,29 +15,29 @@ import Gen.UListRStatus as GRS
main : Program GRS.Send Model Msg
main = Browser.element
- { init = \f -> (init 0 f, Cmd.none)
+ { init = \f -> (init "" f, Cmd.none)
, subscriptions = \model -> DD.sub model.dd
, view = view
, update = update
}
type alias Model =
- { uid : Int
- , rid : Int
+ { uid : String
+ , rid : String
, status : Maybe Int
, empty : String
, state : Api.State
, dd : DD.Config Msg
}
-init : Int -> GRS.Send -> Model
+init : String -> GRS.Send -> Model
init vid f =
{ uid = f.uid
, rid = f.rid
, status = f.status
, empty = f.empty
, state = Api.Normal
- , dd = DD.init ("ulist_reldd" ++ String.fromInt vid ++ "_" ++ String.fromInt f.rid) Open
+ , dd = DD.init ("ulist_reldd" ++ vid ++ "_" ++ f.rid) Open
}
type Msg
diff --git a/elm/UList/SaveDefault.elm b/elm/UList/SaveDefault.elm
index 0ab2cef9..7eed76e0 100644
--- a/elm/UList/SaveDefault.elm
+++ b/elm/UList/SaveDefault.elm
@@ -21,7 +21,7 @@ main = Browser.element
type alias Model =
{ state : Api.State
- , uid : Int
+ , uid : String
, opts : GUSD.SendOpts
, field : String -- Ewwww stringly typed enum
, hid : Bool
diff --git a/elm/UList/VNPage.elm b/elm/UList/VNPage.elm
index 9c1815fb..53921388 100644
--- a/elm/UList/VNPage.elm
+++ b/elm/UList/VNPage.elm
@@ -156,7 +156,7 @@ view model =
, td [] <| notesBut ++
[ case (model.vote.vote /= Nothing && model.flags.canreview, model.flags.review) of
(False, _) -> text ""
- (True, Nothing) -> a [ href ("/v" ++ String.fromInt model.flags.vid ++ "/addreview") ] [ text " write a review »" ]
+ (True, Nothing) -> a [ href ("/" ++ model.flags.vid ++ "/addreview") ] [ text " write a review »" ]
(True, Just w) -> a [ href ("/" ++ w ++ "/edit") ] [ text " edit review »" ]
]
]
diff --git a/elm/UList/VoteEdit.elm b/elm/UList/VoteEdit.elm
index 2ecdde10..2f57dca8 100644
--- a/elm/UList/VoteEdit.elm
+++ b/elm/UList/VoteEdit.elm
@@ -42,12 +42,12 @@ init f =
in
{ state = Api.Normal
, flags = f
- , dd = DD.init ("vote_edit_dd_" ++ String.fromInt f.vid) Open
+ , dd = DD.init ("vote_edit_dd_" ++ f.vid) Open
, text = if List.any (\n -> v == Just (String.fromInt n)) (List.indexedMap (\a b -> a+1) ratings) then "" else Maybe.withDefault "" v
, vote = v
, ovote = v
, isvalid = True
- , fieldId = "vote_edit_" ++ String.fromInt f.vid
+ , fieldId = "vote_edit_" ++ f.vid
}
type Msg
diff --git a/elm/User/Edit.elm b/elm/User/Edit.elm
index 43ec1212..25c5d49d 100644
--- a/elm/User/Edit.elm
+++ b/elm/User/Edit.elm
@@ -32,7 +32,7 @@ type alias PassData =
type alias Model =
{ state : Api.State
- , id : Int
+ , id : String
, title : String
, username : String
, opts : GUE.RecvOpts
@@ -173,7 +173,7 @@ update msg model =
else ({ model | state = Api.Loading }, GUE.send (encode model) Submitted)
-- TODO: This reload is only necessary for the skin and customcss options to apply, but it's nicer to do that directly from JS.
- Submitted GApi.Success -> (model, load <| "/u" ++ String.fromInt model.id ++ "/edit")
+ Submitted GApi.Success -> (model, load <| "/" ++ model.id ++ "/edit")
Submitted GApi.MailChange -> ({ model | mailConfirm = True, state = Api.Normal }, Cmd.none)
Submitted r -> ({ model | state = Api.Error r }, Cmd.none)
diff --git a/elm/User/PassSet.elm b/elm/User/PassSet.elm
index 9ad10748..31e902ea 100644
--- a/elm/User/PassSet.elm
+++ b/elm/User/PassSet.elm
@@ -22,7 +22,7 @@ main = Browser.element
type alias Model =
{ token : String
- , uid : Int
+ , uid : String
, newpass1 : String
, newpass2 : String
, state : Api.State
diff --git a/elm/VNEdit.elm b/elm/VNEdit.elm
index bbb03d41..aab55302 100644
--- a/elm/VNEdit.elm
+++ b/elm/VNEdit.elm
@@ -68,15 +68,15 @@ type alias Model =
, staffSearch : A.Model GApi.ApiStaffResult
, seiyuu : List GVE.RecvSeiyuu
, seiyuuSearch: A.Model GApi.ApiStaffResult
- , seiyuuDef : Int -- character id for newly added seiyuu
- , screenshots : List (Int,Img.Image,Maybe Int) -- internal id, img, rel
+ , seiyuuDef : String -- character id for newly added seiyuu
+ , screenshots : List (Int,Img.Image,Maybe String) -- internal id, img, rel
, scrQueue : List File
- , scrUplRel : Maybe Int
+ , scrUplRel : Maybe String
, scrUplNum : Maybe Int
, scrId : Int -- latest used internal id
, releases : List GVE.RecvReleases
, chars : List GVE.RecvChars
- , id : Maybe Int
+ , id : Maybe String
, dupCheck : Bool
, dupVNs : List GApi.ApiVNResult
}
@@ -105,7 +105,7 @@ init d =
, staffSearch = A.init ""
, seiyuu = d.seiyuu
, seiyuuSearch= A.init ""
- , seiyuuDef = Maybe.withDefault 0 <| List.head <| List.map (\c -> c.id) d.chars
+ , seiyuuDef = Maybe.withDefault "" <| List.head <| List.map (\c -> c.id) d.chars
, screenshots = List.indexedMap (\n i -> (n, Img.info (Just i.info), i.rid)) d.screenshots
, scrQueue = []
, scrUplRel = Nothing
@@ -182,16 +182,16 @@ type Msg
| StaffRole Int String
| StaffNote Int String
| StaffSearch (A.Msg GApi.ApiStaffResult)
- | SeiyuuDef Int
+ | SeiyuuDef String
| SeiyuuDel Int
- | SeiyuuChar Int Int
+ | SeiyuuChar Int String
| SeiyuuNote Int String
| SeiyuuSearch (A.Msg GApi.ApiStaffResult)
- | ScrUplRel (Maybe Int)
+ | ScrUplRel (Maybe String)
| ScrUplSel
| ScrUpl File (List File)
| ScrMsg Int Img.Msg
- | ScrRel Int (Maybe Int)
+ | ScrRel Int (Maybe String)
| ScrDel Int
| DupSubmit
| DupResults GApi.Response
@@ -352,7 +352,7 @@ view model =
[ b [ class "standout" ] [ text "Release titles should not be added as alias." ]
, br [] []
, text "Release: "
- , a [ href <| "/r"++String.fromInt r.id ] [ text r.title ]
+ , a [ href <| "/"++r.id ] [ text r.title ]
, br [] [], br [] []
]
, text "List of alternative titles or abbreviations. One line for each alias. Can include both official (japanese/english) titles and unofficial titles used around net."
@@ -375,8 +375,8 @@ view model =
, formField "Related VNs"
[ if List.isEmpty model.vns then text ""
else table [] <| List.indexedMap (\i v -> tr []
- [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| "v" ++ String.fromInt v.vid ++ ":" ] ]
- , td [ style "text-align" "right"] [ a [ href <| "/v" ++ String.fromInt v.vid ] [ text v.title ] ]
+ [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| v.vid ++ ":" ] ]
+ , td [ style "text-align" "right"] [ a [ href <| "/" ++ v.vid ] [ text v.title ] ]
, td []
[ text "is an "
, label [] [ inputCheck "" v.official (VNOfficial i), text " official" ]
@@ -455,8 +455,8 @@ view model =
]
] ] ]
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 [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| s.id ++ ":" ] ]
+ , td [] [ a [ href <| "/" ++ 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" :: onInvalid (Invalid Staff) :: GVE.valStaffNote) ]
, td [] [ inputButton "remove" (StaffDel n) [] ]
@@ -465,7 +465,7 @@ view model =
cast =
let
- chars = List.map (\c -> (c.id, c.name ++ " (c" ++ String.fromInt c.id ++ ")")) model.chars
+ chars = List.map (\c -> (c.id, c.name ++ " (" ++ c.id ++ ")")) model.chars
head =
if List.isEmpty model.seiyuu then [] else [
thead [] [ tr []
@@ -493,10 +493,10 @@ view model =
] ] ]
item n s = tr []
[ td [] [ inputSelect "" s.cid (SeiyuuChar n) []
- <| chars ++ if List.any (\c -> c.id == s.cid) model.chars then [] else [(s.cid, "[deleted/moved character: c" ++ String.fromInt s.cid ++ "]")] ]
+ <| chars ++ if List.any (\c -> c.id == s.cid) model.chars then [] else [(s.cid, "[deleted/moved character: " ++ s.cid ++ "]")] ]
, td []
- [ b [ class "grayedout" ] [ text <| "s" ++ String.fromInt s.id ++ ":" ]
- , a [ href <| "/s" ++ String.fromInt s.id ] [ text s.name ] ]
+ [ b [ class "grayedout" ] [ text <| s.id ++ ":" ]
+ , a [ href <| "/" ++ s.id ] [ text s.name ] ]
, td [] [ inputText "" s.note (SeiyuuNote n) (style "width" "300px" :: onInvalid (Invalid Cast) :: GVE.valSeiyuuNote) ]
, td [] [ inputButton "remove" (SeiyuuDel n) [] ]
]
@@ -507,14 +507,14 @@ view model =
else if List.isEmpty model.chars && List.isEmpty model.seiyuu
then p []
[ text "This visual novel does not have any characters associated with it (yet). Please "
- , a [ href <| "/v" ++ Maybe.withDefault "" (Maybe.map String.fromInt model.id) ++ "/addchar" ] [ text "add the appropriate character entries" ]
+ , a [ href <| "/" ++ Maybe.withDefault "" model.id ++ "/addchar" ] [ text "add the appropriate character entries" ]
, text " first and then come back to this form to assign voice actors."
]
else table [] <| head ++ [ foot ] ++ List.indexedMap item model.seiyuu
screenshots =
let
- showrel r = "[" ++ (RDate.format (RDate.expand r.released)) ++ " " ++ (String.join "," r.lang) ++ "] " ++ r.title ++ " (r" ++ String.fromInt r.id ++ ")"
+ showrel r = "[" ++ (RDate.format (RDate.expand r.released)) ++ " " ++ (String.join "," r.lang) ++ "] " ++ r.title ++ " (" ++ r.id ++ ")"
rellist = List.map (\r -> (Just r.id, showrel r)) model.releases
scr n (id, i, rel) = (String.fromInt id, tr [] <|
let getdim img = Maybe.map (\nfo -> (nfo.width, nfo.height)) img |> Maybe.withDefault (0,0)
@@ -548,7 +548,7 @@ view model =
, inputSelect "" rel (ScrRel id) [style "width" "500px"] <| rellist ++
case (relnfo, rel) of
(_, Nothing) -> [(Nothing, "[No release selected]")]
- (Nothing, Just r) -> [(Just r, "[Deleted or unlinked release: r" ++ String.fromInt r ++ "]")]
+ (Nothing, Just r) -> [(Just r, "[Deleted or unlinked release: " ++ r ++ "]")]
_ -> []
]
])
@@ -597,7 +597,7 @@ view model =
else if List.isEmpty model.screenshots && List.isEmpty model.releases
then p []
[ text "This visual novel does not have any releases associated with it (yet). Please "
- , a [ href <| "/v" ++ Maybe.withDefault "" (Maybe.map String.fromInt model.id) ++ "/add" ] [ text "add the appropriate release entries" ]
+ , a [ href <| "/" ++ Maybe.withDefault "" model.id ++ "/add" ] [ text "add the appropriate release entries" ]
, text " first and then come back to this form to upload screenshots."
]
else
@@ -617,7 +617,7 @@ view model =
, text "Please check this list to avoid creating a duplicate visual novel entry. "
, text "Be especially wary of items that have been deleted! To see why an entry has been deleted, click on its title."
, ul [] <| List.map (\v -> li []
- [ a [ href <| "/v" ++ String.fromInt v.id ] [ text v.title ]
+ [ a [ href <| "/" ++ v.id ] [ text v.title ]
, if v.hidden then b [ class "standout" ] [ text " (deleted)" ] else text ""
]
) model.dupVNs
diff --git a/lib/Multi/API.pm b/lib/Multi/API.pm
index c41e9873..0c1f3ffb 100644
--- a/lib/Multi/API.pm
+++ b/lib/Multi/API.pm
@@ -5,7 +5,7 @@
package Multi::API;
-use strict;
+use v5.26;
use warnings;
use Multi::Core;
use Socket 'SO_KEEPALIVE', 'SOL_SOCKET', 'IPPROTO_TCP';
@@ -362,6 +362,8 @@ sub parsedate {
sub formatwd { $_[0] ? "Q$_[0]" : undef }
+sub idnum { defined $_[0] ? 1*($_[0] =~ s/^[a-z]+//r) : undef }
+
sub splitarray {
(my $s = shift) =~ s/^{(.*)}$/$1/;
@@ -410,7 +412,7 @@ my %GET_VN = (
sql => 'SELECT %s FROM vn v LEFT JOIN images i ON i.id = v.image WHERE NOT v.hidden AND (%s) %s',
select => 'v.id',
proc => sub {
- $_[0]{id} *= 1
+ $_[0]{id} = idnum $_[0]{id};
},
sortdef => 'id',
sorts => {
@@ -464,7 +466,7 @@ my %GET_VN = (
sub { my($r, $n) = @_;
# link
for my $i (@$r) {
- $i->{anime} = [ grep $i->{id} == $_->{vid}, @$n ];
+ $i->{anime} = [ grep $i->{id} eq $_->{vid}, @$n ];
}
# cleanup
for (@$n) {
@@ -481,10 +483,10 @@ my %GET_VN = (
JOIN vn v ON v.id = vr.vid WHERE vr.id IN(%s)',
sub { my($r, $n) = @_;
for my $i (@$r) {
- $i->{relations} = [ grep $i->{id} == $_->{vid}, @$n ];
+ $i->{relations} = [ grep $i->{id} eq $_->{vid}, @$n ];
}
for (@$n) {
- $_->{id} *= 1;
+ $_->{id} = idnum $_->{id};
$_->{original} ||= undef;
$_->{official} = $_->{official} =~ /t/ ? TRUE : FALSE,
delete $_->{vid};
@@ -501,7 +503,7 @@ my %GET_VN = (
for my $i (@$r) {
$i->{tags} = [ map
[ $_->{id}*1, 1*sprintf('%.2f', $_->{score}), 1*sprintf('%.0f', $_->{spoiler}) ],
- grep $i->{id} == $_->{vid}, @$n ];
+ grep $i->{id} eq $_->{vid}, @$n ];
}
},
]],
@@ -511,11 +513,11 @@ my %GET_VN = (
FROM vn_screenshots vs JOIN images s ON s.id = vs.scr WHERE vs.id IN(%s)',
sub { my($r, $n) = @_;
for my $i (@$r) {
- $i->{screens} = [ grep $i->{id} == $_->{vid}, @$n ];
+ $i->{screens} = [ grep $i->{id} eq $_->{vid}, @$n ];
}
for (@$n) {
$_->{image} = imgurl delete $_->{scr};
- $_->{rid} *= 1;
+ $_->{rid} = idnum $_->{rid};
$_->{nsfw} = !$_->{c_votecount} || $_->{c_sexual_avg} > 0.4 || $_->{c_violence_avg} > 0.4 ? TRUE : FALSE;
$_->{width} *= 1;
$_->{height} *= 1;
@@ -531,11 +533,11 @@ my %GET_VN = (
WHERE vs.id IN(%s) AND NOT s.hidden',
sub { my($r, $n) = @_;
for my $i (@$r) {
- $i->{staff} = [ grep $i->{id} == $_->{id}, @$n ];
+ $i->{staff} = [ grep $i->{id} eq $_->{id}, @$n ];
}
for (@$n) {
$_->{aid} *= 1;
- $_->{sid} *= 1;
+ $_->{sid} = idnum $_->{sid};
$_->{original} ||= undef;
$_->{note} ||= undef;
delete $_->{id};
@@ -546,8 +548,8 @@ my %GET_VN = (
},
filters => {
id => [
- [ 'int' => 'v.id :op: :value:', {qw|= = != <> > > < < <= <= >= >=|}, range => [1,1e6] ],
- [ inta => 'v.id :op:(:value:)', {'=' => 'IN', '!= ' => 'NOT IN'}, range => [1,1e6], join => ',' ],
+ [ 'int' => 'v.id :op: :value:', {qw|= = != <> > > < < <= <= >= >=|}, process => \'v' ],
+ [ inta => 'v.id :op:(:value:)', {'=' => 'IN', '!= ' => 'NOT IN'}, process => \'v', join => ',' ],
],
title => [
[ str => 'v.title :op: :value:', {qw|= = != <>|} ],
@@ -601,7 +603,7 @@ my %GET_RELEASE = (
released => 'r.released %s',
},
proc => sub {
- $_[0]{id} *= 1
+ $_[0]{id} = idnum $_[0]{id};
},
flags => {
basic => {
@@ -616,7 +618,7 @@ my %GET_RELEASE = (
fetch => [[ 'id', 'SELECT id, lang FROM releases_lang WHERE id IN(%s)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{languages} = [ map $i->{id} == $_->{id} ? $_->{lang} : (), @$r ];
+ $i->{languages} = [ map $i->{id} eq $_->{id} ? $_->{lang} : (), @$r ];
}
},
]],
@@ -644,13 +646,13 @@ my %GET_RELEASE = (
[ 'id', 'SELECT id, platform FROM releases_platforms WHERE id IN(%s)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{platforms} = [ map $i->{id} == $_->{id} ? $_->{platform} : (), @$r ];
+ $i->{platforms} = [ map $i->{id} eq $_->{id} ? $_->{platform} : (), @$r ];
}
} ],
[ 'id', 'SELECT id, medium, qty FROM releases_media WHERE id IN(%s)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{media} = [ grep $i->{id} == $_->{id}, @$r ];
+ $i->{media} = [ grep $i->{id} eq $_->{id}, @$r ];
}
for (@$r) {
delete $_->{id};
@@ -664,10 +666,10 @@ my %GET_RELEASE = (
WHERE NOT v.hidden AND rv.id IN(%s)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{vn} = [ grep $i->{id} == $_->{rid}, @$r ];
+ $i->{vn} = [ grep $i->{id} eq $_->{rid}, @$r ];
}
for (@$r) {
- $_->{id}*=1;
+ $_->{id} = idnum $_->{id};
$_->{original} ||= undef;
delete $_->{rid};
}
@@ -679,10 +681,10 @@ my %GET_RELEASE = (
JOIN producers p ON p.id = rp.pid WHERE NOT p.hidden AND rp.id IN(%s)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{producers} = [ grep $i->{id} == $_->{rid}, @$r ];
+ $i->{producers} = [ grep $i->{id} eq $_->{rid}, @$r ];
}
for (@$r) {
- $_->{id}*=1;
+ $_->{id} = idnum $_->{id};
$_->{original} ||= undef;
$_->{developer} = $_->{developer} =~ /^t/ ? TRUE : FALSE;
$_->{publisher} = $_->{publisher} =~ /^t/ ? TRUE : FALSE;
@@ -694,15 +696,15 @@ my %GET_RELEASE = (
},
filters => {
id => [
- [ 'int' => 'r.id :op: :value:', {qw|= = != <> > > >= >= < < <= <=|}, range => [1,1e6] ],
- [ inta => 'r.id :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, join => ',', range => [1,1e6] ],
+ [ 'int' => 'r.id :op: :value:', {qw|= = != <> > > >= >= < < <= <=|}, process => \'r' ],
+ [ inta => 'r.id :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, join => ',', process => \'r' ],
],
vn => [
- [ 'int' => 'r.id :op:(SELECT rv.id FROM releases_vn rv WHERE rv.vid = :value:)', {'=' => 'IN', '!=' => 'NOT IN'}, range => [1,1e6] ],
- [ inta => 'r.id :op:(SELECT rv.id FROM releases_vn rv WHERE rv.vid IN(:value:))', {'=' => 'IN', '!=' => 'NOT IN'}, join => ',', range => [1,1e6] ],
+ [ 'int' => 'r.id :op:(SELECT rv.id FROM releases_vn rv WHERE rv.vid = :value:)', {'=' => 'IN', '!=' => 'NOT IN'}, process => \'v' ],
+ [ inta => 'r.id :op:(SELECT rv.id FROM releases_vn rv WHERE rv.vid IN(:value:))', {'=' => 'IN', '!=' => 'NOT IN'}, join => ',', process => \'v' ],
],
producer => [
- [ 'int' => 'r.id IN(SELECT rp.id FROM releases_producers rp WHERE rp.pid = :value:)', {'=',1}, range => [1,1e6] ],
+ [ 'int' => 'r.id IN(SELECT rp.id FROM releases_producers rp WHERE rp.pid = :value:)', {'=',1}, process => \'p' ],
],
title => [
[ str => 'r.title :op: :value:', {qw|= = != <>|} ],
@@ -745,7 +747,7 @@ my %GET_PRODUCER = (
sql => 'SELECT %s FROM producers p WHERE NOT p.hidden AND (%s) %s',
select => 'p.id',
proc => sub {
- $_[0]{id} *= 1
+ $_[0]{id} = idnum $_[0]{id}
},
sortdef => 'id',
sorts => {
@@ -776,10 +778,10 @@ my %GET_PRODUCER = (
JOIN producers p ON p.id = pl.pid WHERE pl.id IN(%s)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{relations} = [ grep $i->{id} == $_->{pid}, @$r ];
+ $i->{relations} = [ grep $i->{id} eq $_->{pid}, @$r ];
}
for (@$r) {
- $_->{id}*=1;
+ $_->{id} = idnum $_->{id};
$_->{original} ||= undef;
delete $_->{pid};
}
@@ -789,8 +791,8 @@ my %GET_PRODUCER = (
},
filters => {
id => [
- [ 'int' => 'p.id :op: :value:', {qw|= = != <> > > < < <= <= >= >=|}, range => [1,1e6] ],
- [ inta => 'p.id :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, join => ',', range => [1,1e6] ],
+ [ 'int' => 'p.id :op: :value:', {qw|= = != <> > > < < <= <= >= >=|}, process => \'p' ],
+ [ inta => 'p.id :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, join => ',', process => \'p' ],
],
name => [
[ str => 'p.name :op: :value:', {qw|= = != <>|} ],
@@ -819,7 +821,7 @@ my %GET_CHARACTER = (
sql => 'SELECT %s FROM chars c LEFT JOIN images i ON i.id = c.image WHERE NOT c.hidden AND (%s) %s',
select => 'c.id',
proc => sub {
- $_[0]{id} *= 1
+ $_[0]{id} = idnum $_[0]{id};
},
sortdef => 'id',
sorts => {
@@ -857,7 +859,7 @@ my %GET_CHARACTER = (
fetch => [[ 'id', 'SELECT id, tid, spoil FROM chars_traits WHERE id IN(%s)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{traits} = [ map [ $_->{tid}*1, $_->{spoil}*1 ], grep $i->{id} == $_->{id}, @$r ];
+ $i->{traits} = [ map [ $_->{tid}*1, $_->{spoil}*1 ], grep $i->{id} eq $_->{id}, @$r ];
}
},
]],
@@ -866,7 +868,7 @@ my %GET_CHARACTER = (
fetch => [[ 'id', 'SELECT id, vid, rid, spoil, role FROM chars_vns WHERE id IN(%s)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{vns} = [ map [ $_->{vid}*1, ($_->{rid}||0)*1, $_->{spoil}*1, $_->{role} ], grep $i->{id} == $_->{id}, @$r ];
+ $i->{vns} = [ map [ idnum($_->{vid}), idnum($_->{rid}||0), $_->{spoil}*1, $_->{role} ], grep $i->{id} eq $_->{id}, @$r ];
}
},
]],
@@ -877,12 +879,12 @@ my %GET_CHARACTER = (
WHERE vs.cid IN(%s) AND NOT v.hidden AND NOT s.hidden',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{voiced} = [ grep $i->{id} == $_->{cid}, @$r ];
+ $i->{voiced} = [ grep $i->{id} eq $_->{cid}, @$r ];
}
for (@$r) {
- $_->{id}*=1;
+ $_->{id} = idnum $_->{id};
$_->{aid}*=1;
- $_->{vid}*=1;
+ $_->{vid} = idnum $_->{vid};
$_->{note} ||= undef;
delete $_->{cid};
}
@@ -894,10 +896,10 @@ my %GET_CHARACTER = (
UNION SELECT c.main AS cid, c.id, c.name, c.original, c.main_spoil AS spoiler FROM chars c WHERE c.main IN(%1$s)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{instances} = [ grep $i->{id} == $_->{cid} && $_->{id} != $i->{id}, @$r ];
+ $i->{instances} = [ grep $i->{id} eq $_->{cid} && $_->{id} ne $i->{id}, @$r ];
}
for (@$r) {
- $_->{id}*=1;
+ $_->{id} = idnum $_->{id};
$_->{original} ||= undef;
$_->{spoiler}*=1;
delete $_->{cid};
@@ -908,8 +910,8 @@ my %GET_CHARACTER = (
},
filters => {
id => [
- [ 'int' => 'c.id :op: :value:', {qw|= = != <> > > < < <= <= >= >=|}, range => [1,1e6] ],
- [ inta => 'c.id :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, range => [1,1e6], join => ',' ],
+ [ 'int' => 'c.id :op: :value:', {qw|= = != <> > > < < <= <= >= >=|}, process => \'c' ],
+ [ inta => 'c.id :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, process => \'c', join => ',' ],
],
name => [
[ str => 'c.name :op: :value:', {qw|= = != <>|} ],
@@ -924,8 +926,8 @@ my %GET_CHARACTER = (
[ str => '(c.name ILIKE :value: OR c.original ILIKE :value: OR c.alias ILIKE :value:)', {'~',1}, process => \'like' ],
],
vn => [
- [ 'int' => 'c.id IN(SELECT cv.id FROM chars_vns cv WHERE cv.vid = :value:)', {'=',1}, range => [1,1e6] ],
- [ inta => 'c.id IN(SELECT cv.id FROM chars_vns cv WHERE cv.vid IN(:value:))', {'=',1}, range => [1,1e6], join => ',' ],
+ [ 'int' => 'c.id IN(SELECT cv.id FROM chars_vns cv WHERE cv.vid = :value:)', {'=',1}, process => \'v' ],
+ [ inta => 'c.id IN(SELECT cv.id FROM chars_vns cv WHERE cv.vid IN(:value:))', {'=',1}, process => \'v', join => ',' ],
],
traits => [
[ int => 'c.id :op:(SELECT tc.cid FROM traits_chars tc WHERE tc.tid = :value:)', {'=' => 'IN', '!=' => 'NOT IN'}, range => [1,1e6] ],
@@ -939,7 +941,7 @@ my %GET_STAFF = (
sql => 'SELECT %s FROM staff s JOIN staff_alias sa ON sa.aid = s.aid WHERE NOT s.hidden AND (%s) %s',
select => 's.id',
proc => sub {
- $_[0]{id} *= 1
+ $_[0]{id} = idnum $_[0]{id};
},
sortdef => 'id',
sorts => {
@@ -975,7 +977,7 @@ my %GET_STAFF = (
fetch => [[ 'id', 'SELECT id, aid, name, original FROM staff_alias WHERE id IN(%s)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{aliases} = [ map [ $_->{aid}*1, $_->{name}, $_->{original}||undef ], grep $i->{id} == $_->{id}, @$r ];
+ $i->{aliases} = [ map [ $_->{aid}*1, $_->{name}, $_->{original}||undef ], grep $i->{id} eq $_->{id}, @$r ];
}
},
]],
@@ -986,10 +988,10 @@ my %GET_STAFF = (
WHERE sa.id IN(%s) AND NOT v.hidden',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{vns} = [ grep $i->{id} == $_->{sid}, @$r ];
+ $i->{vns} = [ grep $i->{id} eq $_->{sid}, @$r ];
}
for (@$r) {
- $_->{id}*=1;
+ $_->{id} = idnum $_->{id};
$_->{aid}*=1;
$_->{note} ||= undef;
delete $_->{sid};
@@ -1003,12 +1005,12 @@ my %GET_STAFF = (
WHERE sa.id IN(%s) AND NOT v.hidden',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{voiced} = [ grep $i->{id} == $_->{sid}, @$r ];
+ $i->{voiced} = [ grep $i->{id} eq $_->{sid}, @$r ];
}
for (@$r) {
- $_->{id}*=1;
+ $_->{id} = idnum $_->{id};
$_->{aid}*=1;
- $_->{cid}*=1;
+ $_->{cid} = idnum $_->{cid};
$_->{note} ||= undef;
delete $_->{sid};
}
@@ -1018,8 +1020,8 @@ my %GET_STAFF = (
},
filters => {
id => [
- [ 'int' => 's.id :op: :value:', {qw|= = != <> > > < < <= <= >= >=|}, range => [1,1e6] ],
- [ inta => 's.id :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, range => [1,1e6], join => ',' ],
+ [ 'int' => 's.id :op: :value:', {qw|= = != <> > > < < <= <= >= >=|}, process => \'s' ],
+ [ inta => 's.id :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, range => [1,1e6], process => \'s' ],
],
aid => [
[ 'int' => 's.id IN(SELECT sa.id FROM staff_alias sa WHERE sa.aid = :value:)', {'=',1}, range => [1,1e6] ],
@@ -1036,36 +1038,36 @@ my %GET_QUOTE = (
sql => "SELECT %s FROM quotes q JOIN vn v ON v.id = q.vid WHERE NOT v.hidden AND (%s) %s",
select => "v.id, v.title, q.quote",
proc => sub {
- $_[0]{id}*=1;
+ $_[0]{id} = idnum $_[0]{id};
},
sortdef => 'random',
sorts => { id => 'q.vid %s', random => 'RANDOM() %s' },
flags => { basic => {} },
filters => {
id => [
- [ 'int' => 'q.vid :op: :value:', {qw|= = != <> > > >= >= < < <= <=|}, range => [1,1e6] ],
- [ inta => 'q.vid :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, join => ',', range => [1,1e6] ],
+ [ 'int' => 'q.vid :op: :value:', {qw|= = != <> > > >= >= < < <= <=|}, process => \'v' ],
+ [ inta => 'q.vid :op:(:value:)', {'=' => 'IN', '!=' => 'NOT IN'}, join => ',', process => \'v' ],
]
},
);
# All user ID filters consider uid=0 to be the logged in user. Needs a special processing function to handle that.
-sub subst_user_id { my($id, $c) = @_; !$id && !$c->{uid} ? \'Not logged in.' : $id || $c->{uid} }
+sub subst_user_id { my($id, $c) = @_; $id && $id =~ /^[1-9][0-9]{0,6}$/ ? "u$id" : ($c->{uid} || \'Not logged in.') }
my %GET_USER = (
sql => "SELECT %s FROM users u WHERE (%s) %s",
select => "id, username",
proc => sub {
- $_[0]{id}*=1;
+ $_[0]{id} = idnum $_[0]{id};
},
sortdef => 'id',
sorts => { id => 'id %s' },
flags => { basic => {} },
filters => {
id => [
- [ 'int' => 'u.id :op: :value:', {qw|= =|}, range => [0,1e6], process => \&subst_user_id ],
- [ inta => 'u.id IN(:value:)', {'=',1}, range => [0,1e6], join => ',', process => \&subst_user_id ],
+ [ 'int' => 'u.id :op: :value:', {qw|= =|}, process => \&subst_user_id ],
+ [ inta => 'u.id IN(:value:)', {'=',1}, join => ',', process => \&subst_user_id ],
],
username => [
[ str => 'u.username :op: :value:', {qw|= = != <>|} ],
@@ -1077,7 +1079,7 @@ my %GET_USER = (
# the uid filter for votelist/vnlist/wishlist
-my $UID_FILTER = [ 'int' => 'uv.uid :op: :value:', {qw|= =|}, range => [0,1e6], process => \&subst_user_id ];
+my $UID_FILTER = [ 'int' => 'uv.uid :op: :value:', {qw|= =|}, process => \&subst_user_id ];
# Similarly, a filter for 'vid'
my $VN_FILTER = [
@@ -1091,11 +1093,11 @@ my $UV_PUBLIC = 'EXISTS(SELECT 1 FROM ulist_vns_labels uvl JOIN ulist_labels ul
my %GET_VOTELIST = (
islist => 1,
sql => "SELECT %s FROM ulist_vns uv WHERE uv.vote IS NOT NULL AND (%s) AND $UV_PUBLIC %s",
- sqluser => "SELECT %1\$s FROM ulist_vns uv WHERE uv.vote IS NOT NULL AND (%2\$s) AND (uid = %4\$d OR $UV_PUBLIC) %3\$s",
- select => "uid, vid as vn, vote, extract('epoch' from vote_date) AS added",
+ sqluser => "SELECT %1\$s FROM ulist_vns uv WHERE uv.vote IS NOT NULL AND (%2\$s) AND (uid = %4\$s OR $UV_PUBLIC) %3\$s",
+ select => "uid AS uid, vid as vn, vote, extract('epoch' from vote_date) AS added",
proc => sub {
- $_[0]{uid}*=1;
- $_[0]{vn}*=1;
+ $_[0]{uid} = idnum $_[0]{uid};
+ $_[0]{vn} = idnum $_[0]{vn};
$_[0]{vote}*=1;
$_[0]{added} = int $_[0]{added};
},
@@ -1112,11 +1114,11 @@ my $SQL_VNLIST = 'FROM ulist_vns uv LEFT JOIN ulist_vns_labels uvl ON uvl.uid =
my %GET_VNLIST = (
islist => 1,
sql => "SELECT %s $SQL_VNLIST AND (%s) AND $UV_PUBLIC GROUP BY uv.uid, uv.vid, uv.added, uv.notes %s",
- sqluser => "SELECT %1\$s $SQL_VNLIST AND (%2\$s) AND (uv.uid = %4\$d OR $UV_PUBLIC) GROUP BY uv.uid, uv.vid, uv.added, uv.notes %3\$s",
- select => "uv.uid, uv.vid as vn, MAX(uvl.lbl) AS status, extract('epoch' from uv.added) AS added, uv.notes",
+ sqluser => "SELECT %1\$s $SQL_VNLIST AND (%2\$s) AND (uv.uid = %4\$s OR $UV_PUBLIC) GROUP BY uv.uid, uv.vid, uv.added, uv.notes %3\$s",
+ select => "uv.uid AS uid, uv.vid as vn, MAX(uvl.lbl) AS status, extract('epoch' from uv.added) AS added, uv.notes",
proc => sub {
- $_[0]{uid}*=1;
- $_[0]{vn}*=1;
+ $_[0]{uid} = idnum $_[0]{uid};
+ $_[0]{vn} = idnum $_[0]{vn};
$_[0]{status} = defined $_[0]{status} ? $_[0]{status}*1 : 0;
$_[0]{added} = int $_[0]{added};
$_[0]{notes} ||= undef;
@@ -1133,11 +1135,11 @@ my $SQL_WISHLIST = "FROM ulist_vns uv JOIN ulist_vns_labels uvl ON uvl.uid = uv.
my %GET_WISHLIST = (
islist => 1,
sql => "SELECT %s $SQL_WISHLIST AND (%s) AND NOT ul.private GROUP BY uv.uid, uv.vid, uv.added %s",
- sqluser => "SELECT %1\$s $SQL_WISHLIST AND (%2\$s) AND (uv.uid = %4\$d OR NOT ul.private) GROUP BY uv.uid, uv.vid, uv.added %3\$s",
- select => "uv.uid, uv.vid AS vn, MAX(ul.label) AS priority, extract('epoch' from uv.added) AS added",
+ sqluser => "SELECT %1\$s $SQL_WISHLIST AND (%2\$s) AND (uv.uid = %4\$s OR NOT ul.private) GROUP BY uv.uid, uv.vid, uv.added %3\$s",
+ select => "uv.uid AS uid, uv.vid AS vn, MAX(ul.label) AS priority, extract('epoch' from uv.added) AS added",
proc => sub {
- $_[0]{uid}*=1;
- $_[0]{vn}*=1;
+ $_[0]{uid} = idnum $_[0]{uid};
+ $_[0]{vn} = idnum $_[0]{vn};
$_[0]{priority} = {'Wishlist-High' => 0, 'Wishlist-Medium' => 1, 'Wishlist-Low' => 2, 'Blacklist' => 3}->{$_[0]{priority}}//1;
$_[0]{added} = int $_[0]{added};
},
@@ -1150,11 +1152,11 @@ my %GET_WISHLIST = (
my %GET_ULIST_LABELS = (
islist => 1,
sql => 'SELECT %s FROM ulist_labels uv WHERE (%s) AND NOT uv.private %s',
- sqluser => 'SELECT %1$s FROM ulist_labels uv WHERE (%2$s) AND (uv.uid = %4$d OR NOT uv.private) %3$s',
- select => 'uid, id, label, private',
+ sqluser => 'SELECT %1$s FROM ulist_labels uv WHERE (%2$s) AND (uv.uid = %4$s OR NOT uv.private) %3$s',
+ select => 'uid AS uid, id, label, private',
proc => sub {
- $_[0]{uid}*=1;
- $_[0]{id}*=1;
+ $_[0]{uid} = idnum $_[0]{uid};
+ $_[0]{id} = idnum $_[0]{id};
$_[0]{private} = $_[0]{private} =~ /^t/ ? TRUE : FALSE;
},
sortdef => 'id',
@@ -1167,11 +1169,11 @@ my $ULIST_PUBLIC = 'EXISTS(SELECT 1 FROM ulist_vns_labels uvl JOIN ulist_labels
my %GET_ULIST = (
islist => 1,
sql => "SELECT %s FROM ulist_vns uv WHERE (%s) AND ($ULIST_PUBLIC) %s",
- sqluser => "SELECT %1\$s FROM ulist_vns uv WHERE (%2\$s) AND (uv.uid = %4\$d OR $ULIST_PUBLIC) %3\$s",
- select => "uid, vid as vn, extract('epoch' from added) AS added, extract('epoch' from lastmod) AS lastmod, extract('epoch' from vote_date) AS voted, vote, started, finished, notes",
+ sqluser => "SELECT %1\$s FROM ulist_vns uv WHERE (%2\$s) AND (uv.uid = %4\$s OR $ULIST_PUBLIC) %3\$s",
+ select => "uid AS uid, vid as vn, extract('epoch' from added) AS added, extract('epoch' from lastmod) AS lastmod, extract('epoch' from vote_date) AS voted, vote, started, finished, notes",
proc => sub {
- $_[0]{uid}*=1;
- $_[0]{vn}*=1;
+ $_[0]{uid} = idnum $_[0]{uid};
+ $_[0]{vn} = idnum $_[0]{vn};
$_[0]{added} = int $_[0]{added};
$_[0]{lastmod} = int $_[0]{lastmod};
$_[0]{voted} = int $_[0]{voted} if $_[0]{voted};
@@ -1195,10 +1197,10 @@ my %GET_ULIST = (
WHERE (uvl.uid,uvl.vid) IN(%s) AND (NOT ul.private OR uvl.uid = %s OR uvl.lbl = 7)',
sub { my($n, $r) = @_;
for my $i (@$n) {
- $i->{labels} = [ grep $i->{uid} == $_->{uid} && $i->{vn} == $_->{vid}, @$r ];
+ $i->{labels} = [ grep $i->{uid} eq $_->{uid} && $i->{vn} eq $_->{vid}, @$r ];
}
for (@$r) {
- $_->{id}*=1;
+ $_->{id} = idnum $_->{id};
delete $_->{uid};
delete $_->{vid};
}
@@ -1327,6 +1329,9 @@ sub get_filters {
return cerr $c, filter => 'Invalid language code', %e if !$LANGUAGE{$v};
} elsif(${$o{process}} eq 'plat') {
return cerr $c, filter => 'Invalid platform code', %e if !$PLATFORM{$v};
+ } elsif(length ${$o{process}} == 1) {
+ return cerr $c, filter => 'Invalid identifier', %e if $v !~ /^[1-9][0-9]{0,6}$/;
+ $v = ${$o{process}}.$v;
}
}
@@ -1386,7 +1391,7 @@ sub get_mainsql {
$sql = $type->{sqluser} if $c->{uid} && $type->{sqluser};
no if $] >= 5.022, warnings => 'redundant';
- cpg $c, sprintf($sql, $select, $where, $last, $c->{uid}), \@placeholders, sub {
+ cpg $c, sprintf($sql, $select, $where, $last, $c->{uid} ? "'$c->{uid}'" : 'NULL'), \@placeholders, sub {
my @res = $_[0]->rowsAsHashes;
$get->{more} = pop(@res)&&1 if @res > $get->{opt}{results};
$get->{list} = \@res;
@@ -1411,7 +1416,7 @@ sub get_fetch {
my @ids = map { my $d=$_; ref $field ? @{$d}{@$field} : ($d->{$field}) } @{$get->{list}};
my $ids = join ',', map { ref $field ? '('.join(',', map '$'.$ref++, @$field).')' : '$'.$ref++ } 1..@{$get->{list}};
no warnings 'redundant';
- cpg $c, sprintf($need{$n}[1], $ids, $c->{uid}||'NULL'), \@ids, sub {
+ cpg $c, sprintf($need{$n}[1], $ids, $c->{uid} ? "'$c->{uid}'" : 'NULL'), \@ids, sub {
$get->{fetched}{$n} = [ $need{$n}[2], [$_[0]->rowsAsHashes] ];
delete $need{$n};
get_final($c, $type, $get) if !keys %need;
@@ -1487,7 +1492,7 @@ sub set_ulist_ret {
sub set_votelist {
my($c, $obj) = @_;
- return cpg $c, 'UPDATE ulist_vns SET vote = NULL, vote_date = NULL WHERE uid = $1 AND vid = $2', [ $c->{uid}, $obj->{id} ], sub {
+ return cpg $c, 'UPDATE ulist_vns SET vote = NULL, vote_date = NULL WHERE uid = $1 AND vid = $2', [ $c->{uid}, 'v'.$obj->{id} ], sub {
set_ulist_ret $c, $obj
} if !$obj->{opt};
@@ -1496,7 +1501,7 @@ sub set_votelist {
return cerr $c, badarg => 'Invalid vote', field => 'vote' if ref($vv) || !defined($vv) || $vv !~ /^\d+$/ || $vv < 10 || $vv > 100;
cpg $c, 'INSERT INTO ulist_vns (uid, vid, vote, vote_date) VALUES ($1, $2, $3, NOW()) ON CONFLICT (uid, vid) DO UPDATE SET vote = $3, vote_date = NOW(), lastmod = NOW()',
- [ $c->{uid}, $obj->{id}, $vv ], sub { set_ulist_ret $c, $obj; }
+ [ $c->{uid}, 'v'.$obj->{id}, $vv ], sub { set_ulist_ret $c, $obj; }
}
@@ -1504,7 +1509,7 @@ sub set_vnlist {
my($c, $obj) = @_;
# Bug: Also removes from wishlist and votelist.
- return cpg $c, 'DELETE FROM ulist_vns WHERE uid = $1 AND vid = $2', [ $c->{uid}, $obj->{id} ], sub {
+ return cpg $c, 'DELETE FROM ulist_vns WHERE uid = $1 AND vid = $2', [ $c->{uid}, 'v'.$obj->{id} ], sub {
set_ulist_ret $c, $obj;
} if !$obj->{opt};
@@ -1517,11 +1522,11 @@ sub set_vnlist {
$vn ||= '';
cpg $c, 'INSERT INTO ulist_vns (uid, vid, notes) VALUES ($1, $2, $3) ON CONFLICT (uid, vid) DO UPDATE SET lastmod = NOW()'.($en ? ', notes = $3' : ''),
- [ $c->{uid}, $obj->{id}, $vn ], sub {
+ [ $c->{uid}, 'v'.$obj->{id}, $vn ], sub {
if($es) {
- cpg $c, 'DELETE FROM ulist_vns_labels WHERE uid = $1 AND vid = $2 AND lbl IN(1,2,3,4)', [ $c->{uid}, $obj->{id} ], sub {
+ cpg $c, 'DELETE FROM ulist_vns_labels WHERE uid = $1 AND vid = $2 AND lbl IN(1,2,3,4)', [ $c->{uid}, 'v'.$obj->{id} ], sub {
if($vs) {
- cpg $c, 'INSERT INTO ulist_vns_labels (uid, vid, lbl) VALUES($1, $2, $3)', [ $c->{uid}, $obj->{id}, $vs ], sub {
+ cpg $c, 'INSERT INTO ulist_vns_labels (uid, vid, lbl) VALUES($1, $2, $3)', [ $c->{uid}, 'v'.$obj->{id}, $vs ], sub {
set_ulist_ret $c, $obj;
}
} else {
@@ -1542,7 +1547,7 @@ sub set_wishlist {
# Bug: This will make it appear in the vnlist
return cpg $c, "DELETE FROM ulist_vns_labels WHERE uid = \$1 AND vid = \$2 AND $sql_label",
- [ $c->{uid}, $obj->{id} ], sub {
+ [ $c->{uid}, 'v'.$obj->{id} ], sub {
set_ulist_ret $c, $obj;
} if !$obj->{opt};
@@ -1551,12 +1556,12 @@ sub set_wishlist {
return cerr $c, badarg => 'Invalid priority', field => 'priority' if ref($vp) || !defined($vp) || $vp !~ /^[0-3]$/;
# Bug: High/Med/Low statuses are only set if a Wishlist-(High|Medium|Low) label exists; These should probably be created if they don't.
- cpg $c, 'INSERT INTO ulist_vns (uid, vid) VALUES ($1, $2) ON CONFLICT DO NOTHING', [ $c->{uid}, $obj->{id} ], sub {
- cpg $c, "DELETE FROM ulist_vns_labels WHERE uid = \$1 AND vid = \$2 AND $sql_label", [ $c->{uid}, $obj->{id} ], sub {
- cpg $c, 'INSERT INTO ulist_vns_labels (uid, vid, lbl) VALUES($1, $2, $3)', [ $c->{uid}, $obj->{id}, $vp == 3 ? 6 : 5 ], sub {
+ cpg $c, 'INSERT INTO ulist_vns (uid, vid) VALUES ($1, $2) ON CONFLICT DO NOTHING', [ $c->{uid}, 'v'.$obj->{id} ], sub {
+ cpg $c, "DELETE FROM ulist_vns_labels WHERE uid = \$1 AND vid = \$2 AND $sql_label", [ $c->{uid}, 'v'.$obj->{id} ], sub {
+ cpg $c, 'INSERT INTO ulist_vns_labels (uid, vid, lbl) VALUES($1, $2, $3)', [ $c->{uid}, 'v'.$obj->{id}, $vp == 3 ? 6 : 5 ], sub {
if($vp != 3) {
cpg $c, 'INSERT INTO ulist_vns_labels (uid, vid, lbl) SELECT $1, $2, id FROM ulist_labels WHERE uid = $1 AND label = $3',
- [ $c->{uid}, $obj->{id}, ['Wishlist-High', 'Wishlist-Medium', 'Wishlist-Low']->[$vp] ], sub {
+ [ $c->{uid}, 'v'.$obj->{id}, ['Wishlist-High', 'Wishlist-Medium', 'Wishlist-Low']->[$vp] ], sub {
set_ulist_ret $c, $obj;
}
} else {
@@ -1570,13 +1575,13 @@ sub set_wishlist {
sub set_ulist {
my($c, $obj) = @_;
- return cpg $c, 'DELETE FROM ulist_vns WHERE uid = $1 AND vid = $2', [ $c->{uid}, $obj->{id} ], sub {
+ return cpg $c, 'DELETE FROM ulist_vns WHERE uid = $1 AND vid = $2', [ $c->{uid}, 'v'.$obj->{id} ], sub {
set_ulist_ret $c, $obj;
} if !$obj->{opt};
my $opt = $obj->{opt};
my @set;
- my @bind = ($c->{uid}, $obj->{id});
+ my @bind = ($c->{uid}, 'v'.$obj->{id});
if(exists $opt->{vote}) {
return cerr $c, badarg => 'Invalid vote', field => 'vote' if defined($opt->{vote}) && (ref $opt->{vote} || $opt->{vote} !~ /^[0-9]+$/ || $opt->{vote} < 10 || $opt->{vote} > 100);
@@ -1608,18 +1613,18 @@ sub set_ulist {
my %l = map +($_,1), grep $_ != 7, $opt->{labels}->@*;
# XXX: This is ugly. Errors (especially: unknown labels) are ignored and
# the entire set operation ought to run in a single transaction.
- pg_cmd 'SELECT lbl FROM ulist_vns_labels WHERE uid = $1 AND vid = $2', [ $c->{uid}, $obj->{id} ], sub {
+ pg_cmd 'SELECT lbl FROM ulist_vns_labels WHERE uid = $1 AND vid = $2', [ $c->{uid}, 'v'.$obj->{id} ], sub {
return if pg_expect $_[0];
my %ids = map +($_->{lbl}, 1), $_[0]->rowsAsHashes;
- pg_cmd 'INSERT INTO ulist_vns_labels (uid, vid, lbl) VALUES ($1,$2,$3)', [ $c->{uid}, $obj->{id}, $_ ] for grep !$ids{$_}, keys %l;
- pg_cmd 'DELETE FROM ulist_vns_labels WHERE uid = $1 AND vid = $2 AND lbl = $3', [ $c->{uid}, $obj->{id}, $_ ] for grep !$l{$_}, keys %ids;
+ pg_cmd 'INSERT INTO ulist_vns_labels (uid, vid, lbl) VALUES ($1,$2,$3)', [ $c->{uid}, 'v'.$obj->{id}, $_ ] for grep !$ids{$_}, keys %l;
+ pg_cmd 'DELETE FROM ulist_vns_labels WHERE uid = $1 AND vid = $2 AND lbl = $3', [ $c->{uid}, 'v'.$obj->{id}, $_ ] for grep !$l{$_}, keys %ids;
};
}
push @set, 'lastmod = NOW()' if @set || $opt->{labels};
return cerr $c, missing => 'No fields to change' if !@set;
- cpg $c, 'INSERT INTO ulist_vns (uid, vid) VALUES ($1, $2) ON CONFLICT (uid, vid) DO NOTHING', [ $c->{uid}, $obj->{id} ], sub {
+ cpg $c, 'INSERT INTO ulist_vns (uid, vid) VALUES ($1, $2) ON CONFLICT (uid, vid) DO NOTHING', [ $c->{uid}, 'v'.$obj->{id} ], sub {
cpg $c, 'UPDATE ulist_vns SET '.join(',', @set).' WHERE uid = $1 AND vid = $2', \@bind, sub {
set_ulist_ret $c, $obj;
}
diff --git a/lib/Multi/IRC.pm b/lib/Multi/IRC.pm
index 02228d9d..e7e1106a 100644
--- a/lib/Multi/IRC.pm
+++ b/lib/Multi/IRC.pm
@@ -212,7 +212,6 @@ sub set_notify {
# formats and posts database items listed in @res, where each item is a hashref with:
-# type database item in [dvprtugw]
# id database id
# title main name or title of the DB entry
# rev (optional) revision, post number
@@ -239,17 +238,18 @@ sub formatid {
);
for (@$res) {
- my $id = ($_->{id} =~ /^[a-z]/ ? '' : $_->{type}) . $_->{id} . ($_->{rev} ? '.'.$_->{rev} : '');
+ my $id = $_->{id} . ($_->{rev} ? '.'.$_->{rev} : '');
+ my $type = $types{ substr $id, 0, 1 };
# (always) [x+.+]
my @msg = ("$BOLD$c"."[$NORMAL$BOLD$id$c]$NORMAL");
# (only if username key is present) Edit of / New item / reply to / whatever
push @msg, $c.(
- $_->{type} eq 'w' && !$_->{rev} ? 'Review of' :
- $_->{type} eq 'w' ? 'Comment to review of' :
- ($_->{rev}||1) == 1 ? "New $types{$_->{type}}" :
- $_->{type} eq 't' ? 'Reply to' : 'Edit of'
+ $id =~ /^w/ && !$_->{rev} ? 'Review of' :
+ $id =~ /^w/ ? 'Comment to review of' :
+ ($_->{rev}||1) == 1 ? "New $type" :
+ $id =~ /^t/ ? 'Reply to' : 'Edit of'
).$NORMAL if exists $_->{username};
# (always) main title
@@ -277,13 +277,13 @@ sub formatid {
sub handleid {
- my($chan, $t, $id, $rev) = @_;
+ my($chan, $id, $rev) = @_;
# Some common exceptions
- return if grep "$t$id$rev" eq $_, qw|v1 v2 v3 v4 u2 i3 i5 i7 c64|;
+ return if grep $id eq $_, qw|v1 v2 v3 v4 u2 i3 i5 i7 c64|;
return if throttle $O{throt_vndbid}, 'irc_vndbid';
- return if throttle $O{throt_sameid}, "irc_sameid_$t$id$rev";
+ return if throttle $O{throt_sameid}, "irc_sameid_$id.$rev";
my $c = sub {
return if pg_expect $_[0], 1;
@@ -291,31 +291,31 @@ sub handleid {
};
# plain vn/user/producer/thread/tag/trait/release
- pg_cmd 'SELECT $1::text AS type, $2::integer AS id, '.(
- $t eq 'v' ? 'v.title FROM vn v WHERE v.id = $2' :
- $t eq 'u' ? 'u.username AS title FROM users u WHERE u.id = $2' :
- $t eq 'p' ? 'p.name AS title FROM producers p WHERE p.id = $2' :
- $t eq 'c' ? 'c.name AS title FROM chars c WHERE c.id = $2' :
- $t eq 's' ? 'sa.name AS title FROM staff s JOIN staff_alias sa ON sa.aid = s.aid AND sa.id = s.id WHERE s.id = $2' :
- $t eq 't' ? 'title, '.$GETBOARDS.' FROM threads t WHERE NOT t.hidden AND NOT t.private AND t.id = vndbid(\'t\',$2)' :
- $t eq 'g' ? 'name AS title FROM tags WHERE id = $2' :
- $t eq 'i' ? 'name AS title FROM traits WHERE id = $2' :
- $t eq 'd' ? 'title FROM docs WHERE id = $2' :
- $t eq 'w' ? 'v.title, u.username FROM reviews w JOIN vn v ON v.id = w.vid LEFT JOIN users u ON u.id = w.uid WHERE w.id = vndbid(\'w\',$2)' :
- 'r.title FROM releases r WHERE r.id = $2'),
- [ $t, $id ], $c if !$rev && $t =~ /[dvprtugicsw]/;
+ pg_cmd 'SELECT $1::vndbid AS id, '.(
+ $id =~ /^v/ ? 'v.title FROM vn v WHERE v.id = $1' :
+ $id =~ /^u/ ? 'u.username AS title FROM users u WHERE u.id = $1' :
+ $id =~ /^p/ ? 'p.name AS title FROM producers p WHERE p.id = $1' :
+ $id =~ /^c/ ? 'c.name AS title FROM chars c WHERE c.id = $1' :
+ $id =~ /^s/ ? 'sa.name AS title FROM staff s JOIN staff_alias sa ON sa.aid = s.aid AND sa.id = s.id WHERE s.id = $1' :
+ $id =~ /^t/ ? 'title, '.$GETBOARDS.' FROM threads t WHERE NOT t.hidden AND NOT t.private AND t.id = $1' :
+ $id =~ /^g/ ? 'name AS title FROM tags WHERE id = vndbid_num($1)' :
+ $id =~ /^i/ ? 'name AS title FROM traits WHERE id = vndbid_num($1)' :
+ $id =~ /^d/ ? 'title FROM docs WHERE id = $1' :
+ $id =~ /^w/ ? 'v.title, u.username FROM reviews w JOIN vn v ON v.id = w.vid LEFT JOIN users u ON u.id = w.uid WHERE w.id = $1' :
+ 'r.title FROM releases r WHERE r.id = $1'),
+ [ $id ], $c if !$rev && $id =~ /^[dvprtugicsw]/;
# edit/insert of vn/release/producer or discussion board post
- pg_cmd 'SELECT $1::text AS type, $2::integer AS id, $3::integer AS rev, '.(
- $t eq 'v' ? 'vh.title, u.username, c.comments FROM changes c JOIN vn_hist vh ON c.id = vh.chid LEFT JOIN users u ON u.id = c.requester WHERE c.type = \'v\' AND c.itemid = $2 AND c.rev = $3' :
- $t eq 'r' ? 'rh.title, u.username, c.comments FROM changes c JOIN releases_hist rh ON c.id = rh.chid LEFT JOIN users u ON u.id = c.requester WHERE c.type = \'r\' AND c.itemid = $2 AND c.rev = $3' :
- $t eq 'p' ? 'ph.name AS title, u.username, c.comments FROM changes c JOIN producers_hist ph ON c.id = ph.chid LEFT JOIN users u ON u.id = c.requester WHERE c.type = \'p\' AND c.itemid = $2 AND c.rev = $3' :
- $t eq 'c' ? 'ch.name AS title, u.username, c.comments FROM changes c JOIN chars_hist ch ON c.id = ch.chid LEFT JOIN users u ON u.id = c.requester WHERE c.type = \'c\' AND c.itemid = $2 AND c.rev = $3' :
- $t eq 's' ? 'sah.name AS title, u.username, c.comments FROM changes c JOIN staff_hist sh ON c.id = sh.chid LEFT JOIN users u ON u.id = c.requester JOIN staff_alias_hist sah ON sah.chid = c.id AND sah.aid = sh.aid WHERE c.type = \'s\' AND c.itemid = $2 AND c.rev = $3' :
- $t eq 'd' ? 'dh.title, u.username, c.comments FROM changes c JOIN docs_hist dh ON c.id = dh.chid LEFT JOIN users u ON u.id = c.requester WHERE c.type = \'d\' AND c.itemid = $2 AND c.rev = $3' :
- $t eq 'w' ? 'v.title, u.username FROM reviews_posts wp JOIN reviews w ON w.id = wp.id JOIN vn v ON v.id = w.vid LEFT JOIN users u ON u.id = wp.uid WHERE wp.id = vndbid(\'w\',$2) AND wp.num = $3' :
- 't.title, u.username, '.$GETBOARDS.' FROM threads t JOIN threads_posts tp ON tp.tid = t.id LEFT JOIN users u ON u.id = tp.uid WHERE NOT t.hidden AND NOT t.private AND t.id = vndbid(\'t\',$2) AND tp.num = $3'),
- [ $t, $id, $rev], $c if $rev && $t =~ /[dvprtcsw]/;
+ pg_cmd 'SELECT $1::vndbid AS id, $2::integer AS rev, '.(
+ $id =~ /^v/ ? 'vh.title, u.username, c.comments FROM changes c JOIN vn_hist vh ON c.id = vh.chid LEFT JOIN users u ON u.id = c.requester WHERE c.itemid = $1 AND c.rev = $2' :
+ $id =~ /^r/ ? 'rh.title, u.username, c.comments FROM changes c JOIN releases_hist rh ON c.id = rh.chid LEFT JOIN users u ON u.id = c.requester WHERE c.itemid = $1 AND c.rev = $2' :
+ $id =~ /^p/ ? 'ph.name AS title, u.username, c.comments FROM changes c JOIN producers_hist ph ON c.id = ph.chid LEFT JOIN users u ON u.id = c.requester WHERE c.itemid = $1 AND c.rev = $2' :
+ $id =~ /^c/ ? 'ch.name AS title, u.username, c.comments FROM changes c JOIN chars_hist ch ON c.id = ch.chid LEFT JOIN users u ON u.id = c.requester WHERE c.itemid = $1 AND c.rev = $2' :
+ $id =~ /^s/ ? 'sah.name AS title, u.username, c.comments FROM changes c JOIN staff_hist sh ON c.id = sh.chid LEFT JOIN users u ON u.id = c.requester JOIN staff_alias_hist sah ON sah.chid = c.id AND sah.aid = sh.aid WHERE c.itemid = $1 AND c.rev = $2' :
+ $id =~ /^d/ ? 'dh.title, u.username, c.comments FROM changes c JOIN docs_hist dh ON c.id = dh.chid LEFT JOIN users u ON u.id = c.requester WHERE c.itemid = $1 AND c.rev = $2' :
+ $id =~ /^w/ ? 'v.title, u.username FROM reviews_posts wp JOIN reviews w ON w.id = wp.id JOIN vn v ON v.id = w.vid LEFT JOIN users u ON u.id = wp.uid WHERE wp.id = $1 AND wp.num = $2' :
+ 't.title, u.username, '.$GETBOARDS.' FROM threads t JOIN threads_posts tp ON tp.tid = t.id LEFT JOIN users u ON u.id = tp.uid WHERE NOT t.hidden AND NOT t.private AND t.id = $1 AND tp.num = $2'),
+ [ $id, $rev], $c if $rev && $id =~ /^[dvprtcsw]/;
}
@@ -327,8 +327,8 @@ sub vndbid {
my @id; # [ type, id, ref ]
for (split /[, ]/, $msg) {
next if length > 15 or m{[a-z]{3,6}://}i; # weed out URLs and too long things
- push @id, /^(?:.*[^\w]|)([wdvprtcs])([1-9][0-9]*)\.([1-9][0-9]*)(?:[^\w].*|)$/ ? [ $1, $2, $3 ] # x+.+
- : /^(?:.*[^\w]|)([wdvprtugics])([1-9][0-9]*)(?:[^\w].*|)$/ ? [ $1, $2, '' ] : (); # x+
+ push @id, /^(?:.*[^\w]|)([wdvprtcs][1-9][0-9]*)\.([1-9][0-9]*)(?:[^\w].*|)$/ ? [ $1, $2 ] # x+.+
+ : /^(?:.*[^\w]|)([wdvprtugics][1-9][0-9]*)(?:[^\w].*|)$/ ? [ $1, '' ] : (); # x+
}
handleid($chan, @$_) for @id;
}
@@ -343,40 +343,40 @@ sub notify {
my $q = {
rev => q{
- SELECT c.type, c.rev, c.comments, c.id AS lastid, c.itemid AS id,
+ SELECT c.rev, c.comments, c.id AS lastid, c.itemid AS id,
COALESCE(vh.title, rh.title, ph.name, ch.name, sah.name, dh.title) AS title, u.username
FROM changes c
- LEFT JOIN vn_hist vh ON c.type = 'v' AND c.id = vh.chid
- LEFT JOIN releases_hist rh ON c.type = 'r' AND c.id = rh.chid
- LEFT JOIN producers_hist ph ON c.type = 'p' AND c.id = ph.chid
- LEFT JOIN chars_hist ch ON c.type = 'c' AND c.id = ch.chid
- LEFT JOIN staff_hist sh ON c.type = 's' AND c.id = sh.chid
- LEFT JOIN staff_alias_hist sah ON c.type = 's' AND sah.aid = sh.aid AND sah.chid = c.id
- LEFT JOIN docs_hist dh ON c.type = 'd' AND c.id = dh.chid
+ LEFT JOIN vn_hist vh ON vndbid_type(c.itemid) = 'v' AND c.id = vh.chid
+ LEFT JOIN releases_hist rh ON vndbid_type(c.itemid) = 'r' AND c.id = rh.chid
+ LEFT JOIN producers_hist ph ON vndbid_type(c.itemid) = 'p' AND c.id = ph.chid
+ LEFT JOIN chars_hist ch ON vndbid_type(c.itemid) = 'c' AND c.id = ch.chid
+ LEFT JOIN staff_hist sh ON vndbid_type(c.itemid) = 's' AND c.id = sh.chid
+ LEFT JOIN staff_alias_hist sah ON vndbid_type(c.itemid) = 's' AND sah.aid = sh.aid AND sah.chid = c.id
+ LEFT JOIN docs_hist dh ON vndbid_type(c.itemid) = 'd' AND c.id = dh.chid
JOIN users u ON u.id = c.requester
- WHERE c.id > $1 AND c.requester <> 1
+ WHERE c.id > $1 AND c.requester <> 'u1'
ORDER BY c.id},
post => q{
- SELECT 't' AS type, vndbid_num(tp.tid) AS id, tp.num AS rev, t.title, COALESCE(u.username, 'deleted') AS username, tp.date AS lastid, }.$GETBOARDS.q{
+ SELECT tp.tid AS id, tp.num AS rev, t.title, COALESCE(u.username, 'deleted') AS username, tp.date AS lastid, }.$GETBOARDS.q{
FROM threads_posts tp
JOIN threads t ON t.id = tp.tid
LEFT JOIN users u ON u.id = tp.uid
WHERE tp.date > $1 AND tp.num = 1 AND NOT t.hidden AND NOT t.private
ORDER BY tp.date},
trait => q{
- SELECT 'i' AS type, t.id, t.name AS title, u.username, t.id AS lastid
+ SELECT 'i'||t.id AS id, t.name AS title, u.username, t.id AS lastid
FROM traits t
JOIN users u ON u.id = t.addedby
WHERE t.id > $1
ORDER BY t.id},
tag => q{
- SELECT 'g' AS type, t.id, t.name AS title, u.username, t.id AS lastid
+ SELECT 'g'||t.id AS id, t.name AS title, u.username, t.id AS lastid
FROM tags t
JOIN users u ON u.id = t.addedby
WHERE t.id > $1
ORDER BY t.id},
review => q{
- SELECT 'w' AS type, w.id, v.title, u.username, w.id AS lastid
+ SELECT w.id, v.title, u.username, w.id AS lastid
FROM reviews w
JOIN vn v ON v.id = w.vid
LEFT JOIN users u ON u.id = w.uid
@@ -421,7 +421,7 @@ vn => [ 0, 0, sub {
my $w = join ' AND ', map "c_search LIKE \$$_", 1..@q;
pg_cmd qq{
- SELECT 'v'::text AS type, id, title
+ SELECT id, title
FROM vn
WHERE NOT hidden AND $w
ORDER BY title
@@ -440,7 +440,7 @@ p => [ 0, 0, sub {
my($nick, $chan, $q) = @_;
return $irc->send_msg(PRIVMSG => $chan, 'You forgot the search query, dummy~~!') if !$q;
pg_cmd q{
- SELECT 'p'::text AS type, id, name AS title
+ SELECT id, name AS title
FROM producers p
WHERE hidden = FALSE AND (name ILIKE $1 OR original ILIKE $1 OR alias ILIKE $1)
ORDER BY name
diff --git a/lib/Multi/Maintenance.pm b/lib/Multi/Maintenance.pm
index 8515357d..f6e913af 100644
--- a/lib/Multi/Maintenance.pm
+++ b/lib/Multi/Maintenance.pm
@@ -196,7 +196,7 @@ sub vnsearch_update { # id, res, time
pg_cmd 'UPDATE vn SET c_search = $1 WHERE id = $2', [ $t, $id ], sub {
my($res, $t2) = @_;
return if pg_expect $res, 0;
- AE::log info => sprintf 'Updated search cache for v%d (%3dms SQL)', $id, ($time+$t2)*1000;
+ AE::log info => sprintf 'Updated search cache for %s (%3dms SQL)', $id, ($time+$t2)*1000;
vnsearch_check;
};
}
diff --git a/lib/VNDB/BBCode.pm b/lib/VNDB/BBCode.pm
index ecba3e58..fcba62ca 100644
--- a/lib/VNDB/BBCode.pm
+++ b/lib/VNDB/BBCode.pm
@@ -295,7 +295,7 @@ sub bb_subst_links {
my %lookup;
parse $msg, sub {
my($code, $tag) = @_;
- $lookup{$1}{$2} = 1 if $tag eq 'dblink' && $code =~ /^(.)(\d+)/;
+ $lookup{$2}{ $2 eq 'g' || $2 eq 'i' ? $3 : $1 } = 1 if $tag eq 'dblink' && $code =~ /^((.)(\d+))/;
1;
};
return $msg unless %lookup;
@@ -305,15 +305,15 @@ sub bb_subst_links {
v => 'SELECT id, title AS name FROM vn WHERE id IN',
c => 'SELECT id, name FROM chars WHERE id IN',
p => 'SELECT id, name FROM producers WHERE id IN',
- g => 'SELECT id, name FROM tags WHERE id IN',
- i => 'SELECT id, name FROM traits WHERE id IN',
+ g => 'SELECT \'g\'||id AS id, name FROM tags WHERE id IN',
+ i => 'SELECT \'i\'||id AS id, name FROM traits WHERE id IN',
s => 'SELECT s.id, sa.name FROM staff_alias sa JOIN staff s ON s.aid = sa.aid WHERE s.id IN',
};
my %links;
for my $type (keys %$types) {
next if !$lookup{$type};
my $lst = $TUWF::OBJ->dbAlli($types->{$type}, [keys %{$lookup{$type}}]);
- $links{$type . $_->{id}} = $_->{name} for @$lst;
+ $links{$_->{id}} = $_->{name} for @$lst;
}
return $msg unless %links;
diff --git a/lib/VNDB/ExtLinks.pm b/lib/VNDB/ExtLinks.pm
index 34449e12..7c9a98ef 100644
--- a/lib/VNDB/ExtLinks.pm
+++ b/lib/VNDB/ExtLinks.pm
@@ -262,7 +262,7 @@ sub enrich_extlinks {
w 'howlongtobeat';
w 'igdb_game';
l 'l_renai';
- push @links, [ 'VNStat', sprintf('https://vnstat.net/novel/%d', $obj->{id}), undef ] if $obj->{c_votecount}>=20;
+ push @links, [ 'VNStat', sprintf('https://vnstat.net/novel/%d', $obj->{id} =~ s/^.//r), undef ] if $obj->{c_votecount}>=20;
}
# Release links
@@ -315,7 +315,7 @@ sub enrich_extlinks {
w 'mobygames_company';
w 'gamefaqs_company';
w 'doujinshi_author';
- push @links, [ 'VNStat', sprintf('https://vnstat.net/developer/%d', $obj->{id}), undef ];
+ push @links, [ 'VNStat', sprintf('https://vnstat.net/developer/%d', $obj->{id} =~ s/^.//r), undef ];
}
$obj->{extlinks} = \@links
diff --git a/lib/VNDB/Func.pm b/lib/VNDB/Func.pm
index 3211f346..9e051fae 100644
--- a/lib/VNDB/Func.pm
+++ b/lib/VNDB/Func.pm
@@ -12,6 +12,8 @@ use VNDB::Config;
use VNDB::Types;
use VNDB::BBCode;
our @EXPORT = ('bb_format', qw|
+ in
+ idcmp
shorten
resolution
gtintype
@@ -27,6 +29,27 @@ our @EXPORT = ('bb_format', qw|
|);
+# Simple "is this element in the array?" function, using 'eq' to test equality.
+# Supports both an @array and \@array.
+# Usage:
+#
+# my $contains_hi = in 'hi', qw/ a b hi c /; # true
+#
+sub in {
+ my($q, @a) = @_;
+ $_ eq $q && return 1 for map ref $_ eq 'ARRAY' ? @$_ : ($_), @a;
+ 0
+}
+
+
+# Compare two vndbids, using proper numeric order
+sub idcmp($$) {
+ my($a1, $a2) = $_[0] =~ /^([a-z]+)([0-9]+)$/;
+ my($b1, $b2) = $_[1] =~ /^([a-z]+)([0-9]+)$/;
+ $a1 cmp $b1 || $a2 <=> $b2
+}
+
+
sub shorten {
my($str, $len) = @_;
return length($str) > $len ? substr($str, 0, $len-3).'...' : $str;
diff --git a/lib/VNDB/Skins.pm b/lib/VNDB/Skins.pm
index 09df652f..d53eec5b 100644
--- a/lib/VNDB/Skins.pm
+++ b/lib/VNDB/Skins.pm
@@ -14,7 +14,7 @@ sub skins {
my $skin = /\/([^\/]+)\.sass/ ? $1 : die;
my %o;
open my $F, '<:utf8', $_ or die $!;
- if(<$F> !~ qr{^// *userid: *([0-9]+) *name: *(.+)}) {
+ if(<$F> !~ qr{^// *userid: *(u[0-9]+) *name: *(.+)}) {
warn "Invalid skin: $skin\n";
()
} else {
diff --git a/lib/VNWeb/AdvSearch.pm b/lib/VNWeb/AdvSearch.pm
index c42d3423..0d1b1635 100644
--- a/lib/VNWeb/AdvSearch.pm
+++ b/lib/VNWeb/AdvSearch.pm
@@ -322,7 +322,7 @@ f v => 65 => 'on-list', { uint => 1, range => [1,1] }, '=' => sub { auth
f v => 6 => 'developer-id',{ vndbid => 'p' },
'=' => sub { sql 'v.id IN(SELECT rv.vid FROM releases r JOIN releases_vn rv ON rv.id = r.id JOIN releases_producers rp ON rp.id = r.id
- WHERE NOT r.hidden AND rp.pid = vndbid_num(', \$_, ') AND rp.developer)' };
+ WHERE NOT r.hidden AND rp.pid =', \$_, 'AND rp.developer)' };
f v => 8 => 'tag', { type => 'any', func => \&_validate_tag },
compact => sub { my $id = ($_->[0] =~ s/^g//r)*1; $_->[1] == 0 && $_->[2] == 0 ? $id : [ $id, int($_->[2]*5)*3 + $_->[1] ] },
@@ -364,8 +364,8 @@ f r => 4 => 'platform', { required => 0, default => undef, enum => \%PLATFORM }
sql 'r.id', $neg ? 'NOT' : '', 'IN(SELECT id FROM releases_platforms WHERE platform IN', $val, $all && @$val > 1 ? ('GROUP BY id HAVING COUNT(platform) =', \scalar @$val) : (), ')';
};
-f r => 6 => 'developer-id',{ vndbid => 'p' }, '=' => sub { sql 'r.id IN(SELECT id FROM releases_producers WHERE developer AND pid = vndbid_num(', \$_, '))' };
-f r => 17 => 'producer-id', { vndbid => 'p' }, '=' => sub { sql 'r.id IN(SELECT id FROM releases_producers WHERE pid = vndbid_num(', \$_, '))' };
+f r => 6 => 'developer-id',{ vndbid => 'p' }, '=' => sub { sql 'r.id IN(SELECT id FROM releases_producers WHERE developer AND pid =', \$_, ')' };
+f r => 17 => 'producer-id', { vndbid => 'p' }, '=' => sub { sql 'r.id IN(SELECT id FROM releases_producers WHERE pid =', \$_, ')' };
f r => 7 => 'released', { fuzzyrdate => 1 }, sql => sub { sql 'r.released', $_[0], \($_ == 1 ? strftime('%Y%m%d', gmtime) : $_) };
f r => 8 => 'resolution', { type => 'array', length => 2, values => { uint => 1, max => 32767 } },
sql => sub { sql 'NOT r.patch AND r.reso_x', $_[0], \$_->[0], 'AND r.reso_y', $_[0], \$_->[1], $_->[0] ? 'AND r.reso_x > 0' : () };
@@ -425,7 +425,7 @@ f c => 53 => 'vn', 'v', '=' => sub { sql 'c.id IN(SELECT cv.id FROM chars_vn
# Staff filters need both 'staff s' and 'staff_alias sa' - aliases are treated as separate rows.
f s => 2 => 'lang', { enum => \%LANGUAGE }, '=' => sub { sql 's.lang =', \$_ };
-f s => 3 => 'id', { vndbid => 's' }, '=' => sub { sql 's.id = vndbid_num(', \$_, ')' };
+f s => 3 => 'id', { vndbid => 's' }, '=' => sub { sql 's.id = ', \$_ };
f s => 4 => 'gender', { enum => \%GENDER }, '=' => sub { sql 's.gender =', \$_ };
f s => 5 => 'role', { enum => [ 'seiyuu', keys %CREDIT_TYPE ] },
sql_list_grp => sub { $_ eq 'seiyuu' ? undef : '' },
@@ -605,7 +605,7 @@ sub _sql_where_trait {
# Assumption: All labels in a group are for the same uid and label==0 has its own group.
sub _sql_where_label {
my($neg, $all, $val) = @_;
- my $uid = $val->[0][0] =~ s/^u//r;
+ my $uid = $val->[0][0];
my $own = VNWeb::ULists::Lib::ulists_own($uid);
my @lbl = map $_->[1], @$val;
@@ -726,10 +726,10 @@ sub elm_search_query {
my(%o,%ids);
_extract_ids($self->{type}, $self->{query}, \%ids) if $self->{query};
- $o{producers} = [ map +{id => $_=~s/^p//rg}, grep /^p/, keys %ids ];
+ $o{producers} = [ map +{id => $_}, grep /^p/, keys %ids ];
enrich_merge id => 'SELECT id, name, original, hidden FROM producers WHERE id IN', $o{producers};
- $o{staff} = [ map +{id => $_=~s/^s//rg}, grep /^s/, keys %ids ];
+ $o{staff} = [ map +{id => $_}, grep /^s/, keys %ids ];
enrich_merge id => 'SELECT s.id, sa.aid, sa.name, sa.original FROM staff s JOIN staff_alias sa ON sa.aid = s.aid WHERE s.id IN', $o{staff};
$o{tags} = [ map +{id => $_=~s/^g//rg}, grep /^g/, keys %ids ];
@@ -752,7 +752,7 @@ sub elm_ {
my($self) = @_;
state $schema ||= tuwf->compile({ type => 'hash', keys => {
- uid => { uint => 1, required => 0 },
+ uid => { vndbid => 'u', required => 0 },
labels => { aoh => { id => { uint => 1 }, label => {} } },
defaultSpoil => { uint => 1 },
saved => { aoh => { name => {}, query => {} } },
diff --git a/lib/VNWeb/Auth.pm b/lib/VNWeb/Auth.pm
index 694ea18a..08ec4dad 100644
--- a/lib/VNWeb/Auth.pm
+++ b/lib/VNWeb/Auth.pm
@@ -39,7 +39,7 @@ our @EXPORT = ('auth');
sub auth {
tuwf->req->{auth} ||= do {
my $cookie = tuwf->reqCookie('auth')||'';
- my($uid, $token_e) = $cookie =~ /^([a-fA-F0-9]{40})\.?(\d+)$/ ? ($2, sha1_hex pack 'H*', $1) : (0, '');
+ my($uid, $token_e) = $cookie =~ /^([a-fA-F0-9]{40})\.?u?(\d+)$/ ? ('u'.$2, sha1_hex pack 'H*', $1) : (0, '');
my $auth = __PACKAGE__->new();
$auth->_load_session($uid, $token_e);
@@ -53,7 +53,7 @@ sub auth {
# have a lot of influence in this)
TUWF::set log_format => sub {
my(undef, $uri, $msg) = @_;
- sprintf "[%s] %s %s: %s\n", scalar localtime(), $uri, tuwf->req && auth ? 'u'.auth->uid : '-', $msg;
+ sprintf "[%s] %s %s: %s\n", scalar localtime(), $uri, tuwf->req && auth ? auth->uid : '-', $msg;
};
diff --git a/lib/VNWeb/Chars/Edit.pm b/lib/VNWeb/Chars/Edit.pm
index 3d0a357a..5f15afd6 100644
--- a/lib/VNWeb/Chars/Edit.pm
+++ b/lib/VNWeb/Chars/Edit.pm
@@ -6,7 +6,7 @@ use VNWeb::Releases::Lib;
my $FORM = {
- id => { required => 0, id => 1 },
+ id => { required => 0, vndbid => 'c' },
name => { maxlength => 200 },
original => { required => 0, default => '', maxlength => 200 },
alias => { required => 0, default => '', maxlength => 500 },
@@ -23,7 +23,7 @@ my $FORM = {
weight => { required => 0, uint => 1, range => [ 0, 32767 ] },
bloodt => { default => 'unknown', enum => \%BLOOD_TYPE },
cup_size => { required => 0, default => '', enum => \%CUP_SIZE },
- main => { required => 0, id => 1 },
+ main => { required => 0, vndbid => 'c' },
main_spoil => { uint => 1, range => [0,2] },
main_ref => { _when => 'out', anybool => 1 },
main_name => { _when => 'out', default => '' },
@@ -39,8 +39,8 @@ my $FORM = {
new => { _when => 'out', anybool => 1 },
} },
vns => { sort_keys => ['vid', 'rid'], aoh => {
- vid => { id => 1 },
- rid => { id => 1, required => 0 },
+ vid => { vndbid => 'v' },
+ rid => { vndbid => 'r', required => 0 },
spoil => { uint => 1, range => [0,2] },
role => { enum => \%CHAR_ROLE },
title => { _when => 'out' },
@@ -51,7 +51,7 @@ my $FORM = {
authmod => { _when => 'out', anybool => 1 },
editsum => { _when => 'in out', editsum => 1 },
releases => { _when => 'out', aoh => {
- id => { id => 1 },
+ id => { vndbid => 'r' },
rels => $VNWeb::Elm::apis{Releases}[0]
} },
};
@@ -62,7 +62,7 @@ my $FORM_CMP = form_compile cmp => $FORM;
TUWF::get qr{/$RE{crev}/(?<action>edit|copy)} => sub {
- my $e = db_entry c => tuwf->capture('id'), tuwf->capture('rev') or return tuwf->resNotFound;
+ my $e = db_entry tuwf->captures('id', 'rev') or return tuwf->resNotFound;
my $copy = tuwf->capture('action') eq 'copy';
return tuwf->resDenied if !can_edit c => $copy ? {} : $e;
@@ -73,7 +73,7 @@ TUWF::get qr{/$RE{crev}/(?<action>edit|copy)} => sub {
$e->{traits} = [ sort { ($a->{order}//99) <=> ($b->{order}//99) || $a->{name} cmp $b->{name} } grep !$copy || $_->{applicable}, $e->{traits}->@* ];
enrich_merge vid => 'SELECT id AS vid, title FROM vn WHERE id IN', $e->{vns};
- $e->{vns} = [ sort { $a->{title} cmp $b->{title} || $a->{vid} <=> $b->{vid} || ($a->{rid}||0) <=> ($b->{rid}||0) } $e->{vns}->@* ];
+ $e->{vns} = [ sort { $a->{title} cmp $b->{title} || idcmp($a->{vid}, $b->{vid}) || idcmp($a->{rid}||'r0', $b->{rid}||'r0') } $e->{vns}->@* ];
my %vns;
$e->{releases} = [ map !$vns{$_->{vid}}++ ? { id => $_->{vid}, rels => releases_by_vn $_->{vid} } : (), $e->{vns}->@* ];
@@ -86,10 +86,10 @@ TUWF::get qr{/$RE{crev}/(?<action>edit|copy)} => sub {
}
$e->{authmod} = auth->permDbmod;
- $e->{editsum} = $copy ? "Copied from c$e->{id}.$e->{chrev}" : $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision c$e->{id}.$e->{chrev}";
+ $e->{editsum} = $copy ? "Copied from $e->{id}.$e->{chrev}" : $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision $e->{id}.$e->{chrev}";
my $title = ($copy ? 'Copy ' : 'Edit ').$e->{name};
- framework_ title => $title, type => 'c', dbobj => $e, tab => tuwf->capture('action'),
+ framework_ title => $title, dbobj => $e, tab => tuwf->capture('action'),
sub {
editmsg_ c => $e, $title, $copy;
elm_ CharEdit => $FORM_OUT, $copy ? {%$e, id=>undef} : $e;
@@ -117,7 +117,7 @@ TUWF::get qr{/$RE{vid}/addchar}, sub {
elm_api CharEdit => $FORM_OUT, $FORM_IN, sub {
my $data = shift;
my $new = !$data->{id};
- my $e = $new ? { id => 0 } : db_entry c => $data->{id} or return tuwf->resNotFound;
+ my $e = $new ? { id => 0 } : db_entry $data->{id} or return tuwf->resNotFound;
return elm_Unauth if !can_edit c => $e;
if(!auth->permDbmod) {
@@ -128,7 +128,7 @@ elm_api CharEdit => $FORM_OUT, $FORM_IN, sub {
$data->{b_day} = 0 if !$data->{b_month};
$data->{main} = undef if $data->{hidden};
- die "Attempt to set main to self" if $data->{main} && $data->{main} == $e->{id};
+ die "Attempt to set main to self" if $data->{main} && $data->{main} eq $e->{id};
die "Attempt to set main while this character is already referenced." if $data->{main} && tuwf->dbVali('SELECT 1 AS ref FROM chars WHERE main =', \$e->{id});
# It's possible that the referenced character has been deleted since it was added as main, so don't die() on this one, just unset main.
$data->{main} = undef if $data->{main} && !tuwf->dbVali('SELECT 1 FROM chars WHERE NOT hidden AND main IS NULL AND id =', \$data->{main});
@@ -146,12 +146,12 @@ elm_api CharEdit => $FORM_OUT, $FORM_IN, sub {
# and the char hasn't been updated yet. Would be nice to give a better
# error message in that case.
for($data->{vns}->@*) {
- die "Bad release for v$_->{vid}: r$_->{rid}\n" if defined $_->{rid} && !tuwf->dbVali('SELECT 1 FROM releases_vn WHERE id =', \$_->{rid}, 'AND vid =', \$_->{vid});
+ die "Bad release for $_->{vid}: $_->{rid}\n" if defined $_->{rid} && !tuwf->dbVali('SELECT 1 FROM releases_vn WHERE id =', \$_->{rid}, 'AND vid =', \$_->{vid});
}
return elm_Unchanged if !$new && !form_changed $FORM_CMP, $data, $e;
- my($id,undef,$rev) = db_edit c => $e->{id}, $data;
- elm_Redirect "/c$id.$rev";
+ my $ch = db_edit c => $e->{id}, $data;
+ elm_Redirect "/$ch->{nitemid}.$ch->{nrev}";
};
1;
diff --git a/lib/VNWeb/Chars/List.pm b/lib/VNWeb/Chars/List.pm
index 7f48981c..8c01672f 100644
--- a/lib/VNWeb/Chars/List.pm
+++ b/lib/VNWeb/Chars/List.pm
@@ -24,9 +24,9 @@ sub listing_ {
abbr_ class => "icons gen $_->{gender}", title => $GENDER{$_->{gender}}, '' if $_->{gender} ne 'unknown';
};
td_ class => 'tc2', sub {
- a_ href => "/c$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
b_ class => 'grayedout', sub {
- join_ ', ', sub { a_ href => "/v$_->{id}", title => $_->{original}||$_->{title}, $_->{title} }, $_->{vn}->@*;
+ join_ ', ', sub { a_ href => "/$_->{id}", title => $_->{original}||$_->{title}, $_->{title} }, $_->{vn}->@*;
};
};
} for @$list;
@@ -39,17 +39,17 @@ sub listing_ {
div_ sub {
if($_->{image}) {
my($iw,$ih) = imgsize $_->{image}{width}*100, $_->{image}{height}*100, $w, $h;
- image_ $_->{image}, alt => $_->{name}, width => $iw, height => $ih, url => "/c$_->{id}";
+ image_ $_->{image}, alt => $_->{name}, width => $iw, height => $ih, url => "/$_->{id}";
} else {
txt_ 'no image';
}
};
div_ sub {
abbr_ class => "icons gen $_->{gender}", title => $GENDER{$_->{gender}}, '' if $_->{gender} ne 'unknown';
- a_ href => "/c$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
br_;
b_ class => 'grayedout', sub {
- join_ ', ', sub { a_ href => "/v$_->{id}", title => $_->{original}||$_->{title}, $_->{title} }, $_->{vn}->@*;
+ join_ ', ', sub { a_ href => "/$_->{id}", title => $_->{original}||$_->{title}, $_->{title} }, $_->{vn}->@*;
};
};
} for @$list;
@@ -58,11 +58,11 @@ sub listing_ {
div_ class => 'mainbox charbgrid', sub {
my($w,$h) = (160,200);
div_ sub {
- a_ href => "/c$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
div_ sub {
if($_->{image}) {
my($iw,$ih) = imgsize $_->{image}{width}*100, $_->{image}{height}*100, $w, $h;
- image_ $_->{image}, alt => $_->{name}, width => $iw, height => $ih, url => "/c$_->{id}";
+ image_ $_->{image}, alt => $_->{name}, width => $iw, height => $ih, url => "/$_->{id}";
} else {
txt_ 'no image';
}
diff --git a/lib/VNWeb/Chars/Page.pm b/lib/VNWeb/Chars/Page.pm
index eca3e26c..ca18a2f8 100644
--- a/lib/VNWeb/Chars/Page.pm
+++ b/lib/VNWeb/Chars/Page.pm
@@ -26,7 +26,7 @@ sub enrich_item {
'SELECT t.id AS tid, t.name, t.state, t.applicable, t.sexual, coalesce(g.id, t.id) AS group, coalesce(g.name, t.name) AS groupname, coalesce(g.order,0) AS order
FROM traits t LEFT JOIN traits g ON t.group = g.id WHERE t.id IN', $c->{traits};
- $c->{vns} = [ sort { $a->{title} cmp $b->{title} || $a->{vid} <=> $b->{vid} || ($a->{rid}||999999) <=> ($b->{rid}||999999) } $c->{vns}->@* ];
+ $c->{vns} = [ sort { $a->{title} cmp $b->{title} || idcmp($a->{vid}, $b->{vid}) || idcmp($a->{rid}||'r999999', $b->{rid}||'r999999') } $c->{vns}->@* ];
$c->{traits} = [ sort { $a->{order} <=> $b->{order} || $a->{groupname} cmp $b->{groupname} || $a->{name} cmp $b->{name} } $c->{traits}->@* ];
}
@@ -67,7 +67,7 @@ sub fetch_chars {
sub _rev_ {
my($c) = @_;
- revision_ c => $c, \&enrich_item,
+ revision_ $c, \&enrich_item,
[ name => 'Name' ],
[ original => 'Original name' ],
[ alias => 'Aliases' ],
@@ -86,14 +86,14 @@ sub _rev_ {
[ age => 'Age', ],
[ main => 'Instance of', empty => 0, fmt => sub {
my $c = tuwf->dbRowi('SELECT id, name, original FROM chars WHERE id =', \$_);
- a_ href => "/c$c->{id}", title => $c->{name}, "c$c->{id}"
+ a_ href => "/$c->{id}", title => $c->{name}, $c->{id}
} ],
[ main_spoil => 'Spoiler', fmt => sub { txt_ fmtspoil $_ } ],
[ image => 'Image', fmt => sub { image_ $_ } ],
[ vns => 'Visual novels', fmt => sub {
- a_ href => "/v$_->{vid}", title => $_->{original}||$_->{title}, "v$_->{vid}";
+ a_ href => "/$_->{vid}", title => $_->{original}||$_->{title}, $_->{vid};
if($_->{rid}) {
- txt_ ' ['; a_ href => "/r$_->{rid}", "r$_->{rid}"; txt_ ']';
+ txt_ ' ['; a_ href => "/$_->{rid}", $_->{rid}; txt_ ']';
}
txt_ " $CHAR_ROLE{$_->{role}}{txt} (".fmtspoil($_->{spoil}).')';
} ],
@@ -118,7 +118,7 @@ sub chartable_ {
table_ class => 'stripe', sub {
thead_ sub { tr_ sub { td_ colspan => 2, sub {
$link
- ? a_ href => "/c$c->{id}", style => 'margin-right: 10px; font-weight: bold', $c->{name}
+ ? a_ href => "/$c->{id}", style => 'margin-right: 10px; font-weight: bold', $c->{name}
: b_ style => 'margin-right: 10px', $c->{name};
b_ class => 'grayedout', style => 'margin-right: 10px', $c->{original} if $c->{original};
abbr_ class => "icons gen $c->{gender}", title => $GENDER{$c->{gender}}, '' if $c->{gender} ne 'unknown';
@@ -173,7 +173,7 @@ sub chartable_ {
td_ sub {
my @vns;
for(@visvns) {
- push @vns, $_ if !@vns || $vns[$#vns]{vid} != $_->{vid};
+ push @vns, $_ if !@vns || $vns[$#vns]{vid} ne $_->{vid};
push $vns[$#vns]{rels}->@*, $_;
}
join_ \&br_, sub {
@@ -181,18 +181,18 @@ sub chartable_ {
# Just a VN link, no releases
if(!$vn && $v->{rels}->@* == 1 && !$v->{rels}[0]{rid}) {
txt_ $CHAR_ROLE{$v->{role}}{txt}.' - ';
- a_ href => "/v$v->{vid}", title => $v->{original}||$v->{title}, $v->{title};
+ a_ href => "/$v->{vid}", title => $v->{original}||$v->{title}, $v->{title};
spoil_ $v->{spoil};
# With releases
} else {
- a_ href => "/v$v->{vid}", title => $v->{original}||$v->{title}, $v->{title} if !$vn;
+ a_ href => "/$v->{vid}", title => $v->{original}||$v->{title}, $v->{title} if !$vn;
br_ if !$vn;
join_ \&br_, sub {
b_ class => 'grayedout', '> ';
txt_ $CHAR_ROLE{$_->{role}}{txt}.' - ';
if($_->{rid}) {
- b_ class => 'grayedout', "r$_->{rid}:";
- a_ href => "/r$_->{rid}", title => $_->{roriginal}||$_->{rtitle}, $_->{rtitle};
+ b_ class => 'grayedout', "$_->{rid}:";
+ a_ href => "/$_->{rid}", title => $_->{roriginal}||$_->{rtitle}, $_->{rtitle};
} else {
txt_ 'All other releases';
}
@@ -207,7 +207,7 @@ sub chartable_ {
td_ class => 'key', 'Voiced by';
td_ sub {
join_ \&br_, sub {
- a_ href => "/s$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
txt_ " ($_->{note})" if $_->{note};
}, $c->{seiyuu}->@*;
};
@@ -226,7 +226,7 @@ sub chartable_ {
TUWF::get qr{/$RE{crev}} => sub {
- my $c = db_entry c => tuwf->capture('id'), tuwf->capture('rev');
+ my $c = db_entry tuwf->captures('id','rev');
return tuwf->resNotFound if !$c;
enrich_item $c;
@@ -252,7 +252,7 @@ TUWF::get qr{/$RE{crev}} => sub {
# Only display the sexual traits toggle when there are sexual traits within the current spoiler level.
my $has_sex = grep $_->{state} == 2 && $_->{spoil} <= $view->{spoilers} && $_->{sexual}, map $_->{traits}->@*, $c, @$inst;
- framework_ title => $c->{name}, index => !tuwf->capture('rev'), type => 'c', dbobj => $c, hiddenmsg => 1,
+ framework_ title => $c->{name}, index => !tuwf->capture('rev'), dbobj => $c, hiddenmsg => 1,
og => {
description => bb_format($c->{desc}, text => 1),
image => $c->{image} && $c->{image}{votecount} && !$c->{image}{sexual} && !$c->{image}{violence} ? imgurl($c->{image}{id}) : undef,
@@ -260,7 +260,7 @@ TUWF::get qr{/$RE{crev}} => sub {
sub {
_rev_ $c if tuwf->capture('rev');
div_ class => 'mainbox', sub {
- itemmsg_ c => $c;
+ itemmsg_ $c;
h1_ sub { txt_ $c->{name}; debug_ $c };
h2_ class => 'alttitle', $c->{original} if length $c->{original};
p_ class => 'chardetailopts', sub {
diff --git a/lib/VNWeb/Chars/VNTab.pm b/lib/VNWeb/Chars/VNTab.pm
index fbcc9550..6dd9836a 100644
--- a/lib/VNWeb/Chars/VNTab.pm
+++ b/lib/VNWeb/Chars/VNTab.pm
@@ -44,12 +44,12 @@ sub chars_ {
TUWF::get qr{/$RE{vid}/chars}, sub {
- my $v = db_entry v => tuwf->capture('id');
+ my $v = db_entry tuwf->capture('id');
return tuwf->resNotFound if !$v;
VNWeb::VN::Page::enrich_vn($v);
- framework_ title => $v->{title}, index => 1, type => 'v', dbobj => $v, hiddenmsg => 1,
+ framework_ title => $v->{title}, index => 1, dbobj => $v, hiddenmsg => 1,
sub {
VNWeb::VN::Page::infobox_($v);
VNWeb::VN::Page::tabs_($v, 'chars');
diff --git a/lib/VNWeb/DB.pm b/lib/VNWeb/DB.pm
index ecfdae8b..5a9a3a58 100644
--- a/lib/VNWeb/DB.pm
+++ b/lib/VNWeb/DB.pm
@@ -282,16 +282,16 @@ my $entry_types = do {
# - Combine the enrich_merge() calls into a single query.
# - Fixed ordering of arrays (use primary keys)
sub db_entry {
- my($type, $id, $rev) = @_;
- my $t = $entry_types->{$type}||die;
+ my($id, $rev) = @_;
+ my $t = $entry_types->{ substr $id, 0, 1 }||die;
- my $maxrev = tuwf->dbVali('SELECT MAX(rev) FROM changes WHERE type =', \$type, ' AND itemid =', \$id);
+ my $maxrev = tuwf->dbVali('SELECT MAX(rev) FROM changes WHERE itemid =', \$id);
return undef if !$maxrev;
$rev ||= $maxrev;
my $entry = tuwf->dbRowi(q{
SELECT itemid AS id, id AS chid, rev AS chrev, ihid AS hidden, ilock AS locked
FROM changes
- WHERE}, { type => $type, itemid => $id, rev => $rev }
+ WHERE}, { itemid => $id, rev => $rev }
);
return undef if !$entry->{id};
$entry->{maxrev} = $maxrev;
@@ -335,7 +335,7 @@ sub db_edit {
$id ||= undef;
my $t = $entry_types->{$type}||die;
- tuwf->dbExeci("SELECT edit_${type}_init(", \$id, ', (SELECT MAX(rev) FROM changes WHERE type = ', \$type, ' AND itemid = ', \$id, '))');
+ tuwf->dbExeci("SELECT edit_${type}_init(", \$id, ', (SELECT MAX(rev) FROM changes WHERE itemid = ', \$id, '))');
tuwf->dbExeci('UPDATE edit_revision SET', {
requester => $uid // scalar VNWeb::Auth::auth()->uid(),
ip => scalar tuwf->reqIP(),
@@ -372,8 +372,7 @@ sub db_edit {
tuwf->dbExeci("INSERT INTO edit_${base} (", @colnames, ') VALUES ', sql_comma @rows) if @rows;
}
- my $r = tuwf->dbRow("SELECT * FROM edit_${type}_commit()");
- ($r->{itemid}, $r->{chid}, $r->{rev})
+ tuwf->dbRow("SELECT * FROM edit_${type}_commit()");
}
1;
diff --git a/lib/VNWeb/Discussions/Board.pm b/lib/VNWeb/Discussions/Board.pm
index 6262deaf..a5673d49 100644
--- a/lib/VNWeb/Discussions/Board.pm
+++ b/lib/VNWeb/Discussions/Board.pm
@@ -5,18 +5,19 @@ use VNWeb::Discussions::Lib;
TUWF::get qr{/t/(all|$BOARD_RE)}, sub {
- my($type, $id) = tuwf->capture(1) =~ /^([^0-9]+)([0-9]*)$/;
+ my $id = tuwf->capture(1);
+ my($type) = $id =~ /^([^0-9]+)/;
+ $id = undef if $id !~ /[0-9]$/;
my $page = tuwf->validate(get => p => { upage => 1 })->data;
- my $obj = $id ? dbobj $type, $id : undef;
+ my $obj = $id ? dbobj $id : undef;
return tuwf->resNotFound if $id && !$obj->{id};
- my $ititle = $obj && ($obj->{title} || user_displayname $obj);
- my $title = $obj ? "Related discussions for $ititle" : $type eq 'all' ? 'All boards' : $BOARD_TYPE{$type}{txt};
- my $createurl = '/t/'.($id ? $type.$id : $type eq 'db' ? 'db' : 'ge').'/new';
+ my $title = $obj ? "Related discussions for $obj->{title}" : $type eq 'all' ? 'All boards' : $BOARD_TYPE{$type}{txt};
+ my $createurl = '/t/'.($id || ($type eq 'db' ? 'db' : 'ge')).'/new';
- framework_ title => $title, type => $type, dbobj => $obj, tab => 'disc',
+ framework_ title => $title, dbobj => $obj, tab => 'disc',
sub {
div_ class => 'mainbox', sub {
h1_ $title;
@@ -29,7 +30,7 @@ TUWF::get qr{/t/(all|$BOARD_RE)}, sub {
threadlist_
where => $type ne 'all' && sql('t.id IN(SELECT tid FROM threads_boards WHERE type =', \$type, $id ? ('AND iid =', \$id) : (), ')'),
- boards => $type ne 'all' && sql('NOT (tb.type =', \$type, 'AND tb.iid =', \($id||0), ')'),
+ boards => $type ne 'all' && sql('NOT (tb.type =', \$type, 'AND tb.iid IS NOT DISTINCT FROM', \$id, ')'),
results => 50,
sort => $type eq 'an' ? 't.id DESC' : undef,
page => $page,
diff --git a/lib/VNWeb/Discussions/Edit.pm b/lib/VNWeb/Discussions/Edit.pm
index b85514ec..90769d74 100644
--- a/lib/VNWeb/Discussions/Edit.pm
+++ b/lib/VNWeb/Discussions/Edit.pm
@@ -8,11 +8,7 @@ my $FORM = {
tid => { required => 0, vndbid => 't' }, # Thread ID, only when editing a post
title => { required => 0, maxlength => 50 },
- boards => { required => 0, sort_keys => [ 'boardtype', 'iid' ], aoh => {
- btype => { enum => \%BOARD_TYPE },
- iid => { required => 0, default => 0, id => 1 }, #
- title => { required => 0 },
- } },
+ boards => { required => 0, sort_keys => [ 'boardtype', 'iid' ], aoh => $VNWeb::Elm::apis{BoardResult}[0]{aoh} },
poll => { required => 0, type => 'hash', keys => {
question => { maxlength => 100 },
max_options => { uint => 1, min => 1, max => 20 }, #
@@ -54,7 +50,7 @@ elm_api DiscussionsEdit => $FORM_OUT, $FORM_IN, sub {
tuwf->dbExeci('DELETE FROM threads WHERE id =', \$tid);
return elm_Redirect '/t';
}
- auth->audit($t->{user_id}, 'post edit', "edited $tid.1") if $tid && $t->{user_id} != auth->uid;
+ auth->audit($t->{user_id}, 'post edit', "edited $tid.1") if $tid && $t->{user_id} ne auth->uid;
die "Invalid title" if !length $data->{title};
@@ -88,7 +84,7 @@ elm_api DiscussionsEdit => $FORM_OUT, $FORM_IN, sub {
$tid = tuwf->dbVali('INSERT INTO threads', $thread, 'RETURNING id') if !$tid;
tuwf->dbExeci('DELETE FROM threads_boards WHERE tid =', \$tid);
- tuwf->dbExeci('INSERT INTO threads_boards', { tid => $tid, type => $_->{btype}, iid => $_->{iid}//0 }) for $data->{boards}->@*;
+ tuwf->dbExeci('INSERT INTO threads_boards', { tid => $tid, type => $_->{btype}, iid => $_->{iid} }) for $data->{boards}->@*;
if($pollchanged) {
tuwf->dbExeci('DELETE FROM threads_poll_options WHERE tid =', \$tid);
@@ -110,7 +106,9 @@ elm_api DiscussionsEdit => $FORM_OUT, $FORM_IN, sub {
TUWF::get qr{(?:/t/(?<board>$BOARD_RE)/new|/$RE{tid}\.1/edit)}, sub {
- my($board_type, $board_id) = (tuwf->capture('board')||'') =~ /^([^0-9]+)([0-9]*)$/;
+ my $board_id = tuwf->capture('board')||'';
+ my($board_type) = $board_id =~ /^([^0-9]+)/;
+ $board_id = undef if $board_id !~ /[0-9]$/;
my $tid = tuwf->capture('id');
$board_type = 'ge' if $board_type && $board_type eq 'an' && !auth->permBoardmod;
@@ -134,13 +132,13 @@ TUWF::get qr{(?:/t/(?<board>$BOARD_RE)/new|/$RE{tid}\.1/edit)}, sub {
} else {
$t->{boards} = [ {
btype => $board_type,
- iid => $board_id||0,
+ iid => $board_id||undef,
title => !$board_id ? undef :
tuwf->dbVali('SELECT title FROM', sql_boards(), 'x WHERE btype =', \$board_type, 'AND iid =', \$board_id)
} ];
return tuwf->resNotFound if $board_id && !length $t->{boards}[0]{title};
push $t->{boards}->@*, { btype => 'u', iid => auth->uid, title => auth->user->{user_name} }
- if $board_type eq 'u' && $board_id != auth->uid;
+ if $board_type eq 'u' && $board_id ne auth->uid;
}
$t->{can_mod} = auth->permBoardmod;
diff --git a/lib/VNWeb/Discussions/Elm.pm b/lib/VNWeb/Discussions/Elm.pm
index 81fe7a9b..8b39560e 100644
--- a/lib/VNWeb/Discussions/Elm.pm
+++ b/lib/VNWeb/Discussions/Elm.pm
@@ -13,11 +13,11 @@ elm_api Boards => undef, {
my sub subq {
my($prio, $where) = @_;
- sql 'SELECT', $prio, ' AS prio, btype, iid, CASE WHEN iid = 0 THEN NULL ELSE title END AS title
+ sql 'SELECT', $prio, ' AS prio, btype, iid, CASE WHEN iid IS NULL THEN NULL ELSE title END AS title
FROM (',
sql_join('UNION ALL',
sql('SELECT btype, iid, title, original FROM', sql_boards(), 'a'),
- map sql('SELECT', \$_, '::board_type, 0,', \$BOARD_TYPE{$_}{txt}, q{, ''}),
+ map sql('SELECT', \$_, '::board_type, NULL,', \$BOARD_TYPE{$_}{txt}, q{, ''}),
grep !$BOARD_TYPE{$_}{dbitem} && ($BOARD_TYPE{$_}{post_perm} eq 'board' || auth->permBoardmod),
keys %BOARD_TYPE
),
@@ -30,8 +30,8 @@ elm_api Boards => undef, {
FROM (',
sql_join('UNION ALL',
# ID match
- $q =~ /^($BOARD_RE)$/ && $q =~ /^([a-z]+)([0-9]*)$/
- ? subq(0, sql_and sql('btype =', \"$1"), $2 ? sql('iid =', \"$2") : ()) : (),
+ $q =~ /^($BOARD_RE)$/ && $q =~ /^(([a-z]+)[0-9]*)$/
+ ? subq(0, sql_and sql('btype =', \"$2"), $1 ne $2 ? sql('iid =', \"$1") : ()) : (),
subq(
sql('1+LEAST(substr_score(lower(title),', \$qs, '), substr_score(lower(original),', \$qs, '))'),
sql('title ILIKE', \"%$qs%", ' OR original ILIKE', \"%$qs%")
diff --git a/lib/VNWeb/Discussions/Index.pm b/lib/VNWeb/Discussions/Index.pm
index 90ac31b1..920aa934 100644
--- a/lib/VNWeb/Discussions/Index.pm
+++ b/lib/VNWeb/Discussions/Index.pm
@@ -23,7 +23,7 @@ TUWF::get qr{/t}, sub {
};
threadlist_
where => sql('t.id IN(SELECT tid FROM threads_boards WHERE type =', \$b, ')'),
- boards => sql('NOT (tb.type =', \$b, 'AND tb.iid = 0)'),
+ boards => sql('NOT (tb.type =', \$b, 'AND tb.iid IS NULL)'),
results => $BOARD_TYPE{$b}{index_rows},
page => 1;
}
diff --git a/lib/VNWeb/Discussions/Lib.pm b/lib/VNWeb/Discussions/Lib.pm
index 986ce90a..574c8c18 100644
--- a/lib/VNWeb/Discussions/Lib.pm
+++ b/lib/VNWeb/Discussions/Lib.pm
@@ -11,7 +11,7 @@ our $BOARD_RE = join '|', map $_.($BOARD_TYPE{$_}{dbitem}?'(?:[1-9][0-9]{0,5})?'
# Returns a WHERE condition to filter threads that the current user is allowed to see.
sub sql_visible_threads {
- return '1=1' if auth && auth->uid == 2; # Yorhel sees everything
+ return '1=1' if auth && auth->uid eq 'u2'; # Yorhel sees everything
sql_and
auth->permBoardmod ? () : ('NOT t.hidden'),
sql('NOT t.private OR EXISTS(SELECT 1 FROM threads_boards WHERE tid = t.id AND type = \'u\' AND iid =', \auth->uid, ')');
@@ -93,7 +93,7 @@ sub threadlist_ {
};
b_ class => 'boards', sub {
join_ ', ', sub {
- a_ href => "/t/$_->{btype}".($_->{iid}||''),
+ a_ href => '/t/'.($_->{iid}||$_->{btype}),
title => $_->{original}||$BOARD_TYPE{$_->{btype}}{txt},
shorten $_->{title}||$BOARD_TYPE{$_->{btype}}{txt}, 30;
}, $l->{boards}->@[0 .. min 4, $#{$l->{boards}}];
diff --git a/lib/VNWeb/Discussions/PostEdit.pm b/lib/VNWeb/Discussions/PostEdit.pm
index 520a215f..e740c029 100644
--- a/lib/VNWeb/Discussions/PostEdit.pm
+++ b/lib/VNWeb/Discussions/PostEdit.pm
@@ -52,7 +52,7 @@ elm_api DiscussionsPostEdit => $FORM_OUT, $FORM_IN, sub {
tuwf->dbExeci('DELETE FROM reviews_posts WHERE id =', \$id, 'AND num =', \$num);
return elm_Redirect "/$id";
}
- auth->audit($t->{user_id}, 'post edit', "edited $id.$num") if $t->{user_id} != auth->uid;
+ auth->audit($t->{user_id}, 'post edit', "edited $id.$num") if $t->{user_id} ne auth->uid;
my $post = {
tid => $id,
diff --git a/lib/VNWeb/Discussions/Thread.pm b/lib/VNWeb/Discussions/Thread.pm
index 94bf7d02..3836bd46 100644
--- a/lib/VNWeb/Discussions/Thread.pm
+++ b/lib/VNWeb/Discussions/Thread.pm
@@ -80,10 +80,10 @@ sub metabox_ {
a_ href => "/t/$_->{btype}", $BOARD_TYPE{$_->{btype}}{txt};
if($_->{iid}) {
txt_ ' > ';
- a_ style => 'font-weight: bold', href => "/t/$_->{btype}$_->{iid}", "$_->{btype}$_->{iid}";
+ a_ style => 'font-weight: bold', href => "/t/$_->{iid}", $_->{iid};
txt_ ':';
if($_->{title}) {
- a_ href => "/$_->{btype}$_->{iid}", title => $_->{original}||$_->{title}, $_->{title};
+ a_ href => "/$_->{iid}", title => $_->{original}||$_->{title}, $_->{title};
} else {
b_ '[deleted]';
}
diff --git a/lib/VNWeb/Discussions/UPosts.pm b/lib/VNWeb/Discussions/UPosts.pm
index d3bfa95c..955f0790 100644
--- a/lib/VNWeb/Discussions/UPosts.pm
+++ b/lib/VNWeb/Discussions/UPosts.pm
@@ -59,7 +59,7 @@ TUWF::get qr{/$RE{uid}/posts}, sub {
FROM ', $sql, 'ORDER BY date DESC'
);
- my $own = auth && $u->{id} == auth->uid;
+ my $own = auth && $u->{id} eq auth->uid;
my $title = $own ? 'My posts' : 'Posts by '.user_displayname $u;
framework_ title => $title, type => 'u', dbobj => $u, tab => 'posts',
sub {
diff --git a/lib/VNWeb/Docs/Edit.pm b/lib/VNWeb/Docs/Edit.pm
index dfab77a3..f4551dae 100644
--- a/lib/VNWeb/Docs/Edit.pm
+++ b/lib/VNWeb/Docs/Edit.pm
@@ -5,7 +5,7 @@ use VNWeb::Docs::Lib;
my $FORM = {
- id => { id => 1 },
+ id => { vndbid => 'd' },
title => { maxlength => 200 },
content => { required => 0, default => '' },
hidden => { anybool => 1 },
@@ -20,12 +20,12 @@ my $FORM_CMP = form_compile cmp => $FORM;
TUWF::get qr{/$RE{drev}/edit} => sub {
- my $d = db_entry d => tuwf->capture('id'), tuwf->capture('rev') or return tuwf->resNotFound;
+ my $d = db_entry tuwf->captures('id', 'rev') or return tuwf->resNotFound;
return tuwf->resDenied if !can_edit d => $d;
- $d->{editsum} = $d->{chrev} == $d->{maxrev} ? '' : "Reverted to revision d$d->{id}.$d->{chrev}";
+ $d->{editsum} = $d->{chrev} == $d->{maxrev} ? '' : "Reverted to revision $d->{id}.$d->{chrev}";
- framework_ title => "Edit $d->{title}", type => 'd', dbobj => $d, tab => 'edit',
+ framework_ title => "Edit $d->{title}", dbobj => $d, tab => 'edit',
sub {
elm_ DocEdit => $FORM_OUT, $d;
};
@@ -34,14 +34,14 @@ TUWF::get qr{/$RE{drev}/edit} => sub {
elm_api DocEdit => $FORM_OUT, $FORM_IN, sub {
my $data = shift;
- my $doc = db_entry d => $data->{id} or return tuwf->resNotFound;
+ my $doc = db_entry $data->{id} or return tuwf->resNotFound;
return elm_Unauth if !can_edit d => $doc;
return elm_Unchanged if !form_changed $FORM_CMP, $data, $doc;
$data->{html} = md2html $data->{content};
- my($id,undef,$rev) = db_edit d => $doc->{id}, $data;
- elm_Redirect "/d$id.$rev";
+ my $c = db_edit d => $doc->{id}, $data;
+ elm_Redirect "/$c->{nitemid}.$c->{nrev}";
};
diff --git a/lib/VNWeb/Docs/Lib.pm b/lib/VNWeb/Docs/Lib.pm
index 6c7351d4..2f2b273c 100644
--- a/lib/VNWeb/Docs/Lib.pm
+++ b/lib/VNWeb/Docs/Lib.pm
@@ -16,7 +16,7 @@ sub _moderators {
xml_string sub {
dl_ sub {
for my $u (@$l) {
- dt_ sub { a_ href => "/u$u->{id}", $u->{username} };
+ dt_ sub { a_ href => "/$u->{id}", $u->{username} };
dd_ @special_perms == grep($u->{"perm_$_"}, @special_perms) ? 'admin'
: join ', ', grep $u->{"perm_$_"}, @special_perms;
}
@@ -35,7 +35,7 @@ sub _skincontrib {
xml_string sub {
dl_ sub {
for my $u (@$u) {
- dt_ sub { a_ href => "/u$u->{id}", $u->{username} };
+ dt_ sub { a_ href => "/$u->{id}", $u->{username} };
dd_ sub {
join_ ', ', sub { a_ href => "?skin=$_->[0]", $_->[1] }, $users{$u->{id}}->@*
}
diff --git a/lib/VNWeb/Docs/Page.pm b/lib/VNWeb/Docs/Page.pm
index eeda0d00..29b7ec5a 100644
--- a/lib/VNWeb/Docs/Page.pm
+++ b/lib/VNWeb/Docs/Page.pm
@@ -32,21 +32,21 @@ sub _index_ {
sub _rev_ {
my $d = shift;
- revision_ d => $d, sub {},
+ revision_ $d, sub {},
[ title => 'Title' ],
[ content => 'Contents' ];
}
TUWF::get qr{/$RE{drev}} => sub {
- my $d = db_entry d => tuwf->capture('id'), tuwf->capture('rev');
+ my $d = db_entry tuwf->captures('id', 'rev');
return tuwf->resNotFound if !$d;
- framework_ title => $d->{title}, index => !tuwf->capture('rev'), type => 'd', dbobj => $d, hiddenmsg => 1,
+ framework_ title => $d->{title}, index => !tuwf->capture('rev'), dbobj => $d, hiddenmsg => 1,
sub {
_rev_ $d if tuwf->capture('rev');
div_ class => 'mainbox', sub {
- itemmsg_ d => $d;
+ itemmsg_ $d;
h1_ $d->{title};
div_ class => 'docs', sub {
_index_;
diff --git a/lib/VNWeb/Elm.pm b/lib/VNWeb/Elm.pm
index 04a05100..62f7aaf0 100644
--- a/lib/VNWeb/Elm.pm
+++ b/lib/VNWeb/Elm.pm
@@ -58,7 +58,7 @@ our %apis = (
name => {},
} } ],
Releases => [ { aoh => { # Response to 'Release'
- id => { id => 1 },
+ id => { vndbid => 'r' },
title => {},
original => { required => 0, default => '' },
released => { uint => 1 },
@@ -77,8 +77,8 @@ our %apis = (
count => { uint => 1 },
} } ],
BoardResult => [ { aoh => { # Response to 'Boards'
- btype => {},
- iid => { required => 0, default => 0, id => 1 },
+ btype => { enum => \%BOARD_TYPE },
+ iid => { required => 0, vndbid => ['p','v','u'] },
title => { required => 0 },
} } ],
TagResult => [ { aoh => { # Response to 'Tags'
@@ -99,29 +99,29 @@ our %apis = (
group_name => { required => 0 },
} } ],
VNResult => [ { aoh => { # Response to 'VN'
- id => { id => 1 },
+ id => { vndbid => 'v' },
title => {},
original => { required => 0, default => '' },
hidden => { anybool => 1 },
} } ],
ProducerResult => [ { aoh => { # Response to 'Producers'
- id => { id => 1 },
+ id => { vndbid => 'p' },
name => {},
original => { required => 0, default => '' },
hidden => { anybool => 1 },
} } ],
StaffResult => [ { aoh => { # Response to 'Staff'
- id => { id => 1 },
+ id => { vndbid => 's' },
aid => { id => 1 },
name => {},
original => { required => 0, default => '' },
} } ],
CharResult => [ { aoh => { # Response to 'Chars'
- id => { id => 1 },
+ id => { vndbid => 'c' },
name => {},
original => { required => 0, default => '' },
main => { required => 0, type => 'hash', keys => {
- id => { id => 1 },
+ id => { vndbid => 'c' },
name => {},
original => { required => 0, default => '' },
} }
@@ -132,7 +132,7 @@ our %apis = (
original => { required => 0, default => '' },
} } ],
ImageResult => [ { aoh => { # Response to 'Images'
- id => { }, # image id...
+ id => { vndbid => ['ch','cv','sf'] },
token => { required => 0 },
width => { uint => 1 },
height => { uint => 1 },
@@ -150,7 +150,7 @@ our %apis = (
} },
votes => { unique => 0, aoh => {
user => {},
- uid => { uint => 1, required => 0 },
+ uid => { vndbid => 'u', required => 0 },
sexual => { uint => 1 },
violence => { uint => 1 },
ignore => { anybool => 1 },
diff --git a/lib/VNWeb/Graph.pm b/lib/VNWeb/Graph.pm
index 1e826a70..d25bd61c 100644
--- a/lib/VNWeb/Graph.pm
+++ b/lib/VNWeb/Graph.pm
@@ -9,6 +9,7 @@ use Encode 'encode_utf8', 'decode_utf8';
use Exporter 'import';
use List::Util 'max';
use VNDB::Config;
+use VNDB::Func 'idcmp';
our @EXPORT = qw/gen_nodes dot2svg val_escape node_more gen_dot/;
@@ -91,7 +92,7 @@ sub gen_dot {
my $rankdir = $max_fanout > 6 ? 'LR' : 'TB';
for (@$rel) {
- next if $_->{id0} < $_->{id1};
+ next if idcmp($_->{id0}, $_->{id1}) < 0;
my $r1 = $rel_types->{$_->{relation}};
my $r2 = $rel_types->{ $r1->{reverse} };
my $style = exists $_->{official} && !$_->{official} ? 'style="dotted", ' : '';
diff --git a/lib/VNWeb/HTML.pm b/lib/VNWeb/HTML.pm
index 8d9c21eb..132e46fa 100644
--- a/lib/VNWeb/HTML.pm
+++ b/lib/VNWeb/HTML.pm
@@ -75,7 +75,7 @@ sub user_ {
return b_ class => 'grayedout', 'anonymous' if !f 'id';
my $fancy = !(auth->pref('nodistract_can') && auth->pref('nodistract_nofancy'));
my $uniname = f 'uniname_can' && f 'uniname';
- a_ href => '/u'.f('id'),
+ a_ href => '/'.f('id'),
$fancy && $uniname ? (title => f('name'), $uniname) :
(!$fancy && $uniname ? (title => $uniname) : (), $capital ? ucfirst f 'name' : f 'name');
txt_ '⭐' if $fancy && f 'support_can' && f 'support_enabled';
@@ -229,7 +229,7 @@ sub _menu_ {
};
div_ class => 'menubox', sub {
- my $uid = sprintf '/u%d', auth->uid;
+ my $uid = '/'.auth->uid;
my $nc = auth && tuwf->dbVali('SELECT count(*) FROM notifications WHERE uid =', \auth->uid, 'AND read IS NULL');
h2_ sub { user_ auth->user, 'user_', 1 };
div_ sub {
@@ -303,7 +303,7 @@ sub _footer_ {
my $q = tuwf->dbRow('SELECT vid, quote FROM quotes ORDER BY RANDOM() LIMIT 1');
if($q && $q->{vid}) {
lit_ '"';
- a_ href => "/v$q->{vid}", style => 'text-decoration: none', $q->{quote};
+ a_ href => "/$q->{vid}", style => 'text-decoration: none', $q->{quote};
txt_ '"';
br_;
}
@@ -357,7 +357,7 @@ sub _maintabs_subscribe_ {
) x(x)')
: $id =~ /^[vrpcsd]/ && auth->pref('notify_dbedit') && tuwf->dbVali('
- SELECT 1 FROM changes WHERE type = vndbid_type(', \$id, ')::dbentry_type AND itemid = vndbid_num(', \$id, ') AND requester =', \auth->uid);
+ SELECT 1 FROM changes WHERE itemid =', \$id, 'AND requester =', \auth->uid);
my $sub = tuwf->dbRowi('SELECT subnum, subreview, subapply FROM notification_subs WHERE uid =', \auth->uid, 'AND iid =', \$id);
@@ -415,7 +415,7 @@ sub _maintabs_ {
SELECT COUNT(*)
FROM threads_boards tb
JOIN threads t ON t.id = tb.tid
- WHERE tb.type =}, \$t, 'AND tb.iid =', \$o->{id}, 'AND', VNWeb::Discussions::Lib::sql_visible_threads());
+ WHERE tb.type =}, \$t, 'AND tb.iid =', \$o->{id}, ' AND', VNWeb::Discussions::Lib::sql_visible_threads());
t disc => "/t/$id", "discussions ($cnt)";
};
@@ -429,9 +429,9 @@ sub _maintabs_ {
# Attempt to figure out the board id from a database entry ($type, $dbobj) combination
sub _board_id {
my($type, $obj) = @_;
- $type =~ /[vp]/ ? $type.$obj->{id} :
- $type eq 'r' && $obj->{vn}->@* ? 'v'.$obj->{vn}[0]{vid} :
- $type eq 'c' && $obj->{vns}->@* ? 'v'.$obj->{vns}[0]{vid} : 'db';
+ $type =~ /[vp]/ ? $obj->{id} :
+ $type eq 'r' && $obj->{vn}->@* ? $obj->{vn}[0]{vid} :
+ $type eq 'c' && $obj->{vns}->@* ? $obj->{vns}[0]{vid} : 'db';
}
@@ -445,7 +445,7 @@ sub _hidden_msg_ {
my $msg = tuwf->dbVali(
'SELECT comments
FROM changes
- WHERE', { type => $o->{type}, itemid => $o->{dbobj}{id} },
+ WHERE itemid =', \$o->{dbobj}{id},
'ORDER BY id DESC LIMIT 1'
);
div_ class => 'mainbox', sub {
@@ -455,7 +455,7 @@ sub _hidden_msg_ {
p_ sub {
if($o->{type} eq 'r' && $o->{dbobj}{vn}) {
txt_ 'This was a release entry for ';
- join_ ',', sub { a_ href => "/v$_->{vid}", $_->{title} }, $o->{dbobj}{vn}->@*;
+ join_ ',', sub { a_ href => "/$_->{vid}", $_->{title} }, $o->{dbobj}{vn}->@*;
txt_ '.';
br_;
}
@@ -479,7 +479,7 @@ sub _hidden_msg_ {
# js => 1/0, set to 1 to ensure 'plain.js' is included on the page even if no elm_() modules are loaded.
# search => $query
# og => { opengraph metadata }
-# type => Database entry type (used for the main tabs & hidden message)
+# type => Database entry type (used for the main tabs & hidden message) (obsolete, inferred from dbobj->{id})
# dbobj => Database entry object (used for the main tabs & hidden message)
# Recognized object fields: id, entry_hidden, entry_locked
# tab => Current tab, or empty for the main tab
@@ -491,6 +491,7 @@ sub framework_ {
my %o = @_;
tuwf->req->{pagevars} = { $o{pagevars}->%* } if $o{pagevars};
tuwf->req->{js} ||= $o{js};
+ $o{type} ||= $1 if $o{dbobj} && $o{dbobj}{id} =~ /^([a-z])/;
html_ lang => 'en', sub {
head_ sub { _head_ \%o };
@@ -517,15 +518,15 @@ sub framework_ {
sub _revision_header_ {
- my($type, $obj) = @_;
+ my($obj) = @_;
b_ "Revision $obj->{chrev}";
debug_ $obj;
if(auth) {
lit_ ' (';
- a_ href => "/$type$obj->{id}.$obj->{chrev}/edit", $obj->{chrev} == $obj->{maxrev} ? 'edit' : 'revert to';
+ a_ href => "/$obj->{id}.$obj->{chrev}/edit", $obj->{chrev} == $obj->{maxrev} ? 'edit' : 'revert to';
if($obj->{rev_user_id}) {
lit_ ' / ';
- a_ href => "/t/u$obj->{rev_user_id}/new?title=Regarding%20$type$obj->{id}.$obj->{chrev}", 'msg user';
+ a_ href => "/t/$obj->{rev_user_id}/new?title=Regarding%20$obj->{id}.$obj->{chrev}", 'msg user';
}
lit_ ')';
}
@@ -613,7 +614,7 @@ sub _stringify_scalars_rec {
}
sub _revision_diff_ {
- my($type, $old, $new, $field, $name, %opt) = @_;
+ my($old, $new, $field, $name, %opt) = @_;
# First do a diff on the raw field elements.
# (if the field is a scalar, it's considered a single element and the diff just tests equality)
@@ -647,14 +648,14 @@ sub _revision_diff_ {
sub _revision_cmp_ {
- my($type, $old, $new, @fields) = @_;
+ my($old, $new, @fields) = @_;
table_ class => 'stripe', sub {
thead_ sub {
tr_ sub {
td_ ' ';
- td_ sub { _revision_header_ $type, $old };
- td_ sub { _revision_header_ $type, $new };
+ td_ sub { _revision_header_ $old };
+ td_ sub { _revision_header_ $new };
};
tr_ sub {
td_ ' ';
@@ -666,7 +667,7 @@ sub _revision_cmp_ {
};
};
};
- _revision_diff_ $type, $old, $new, @$_ for(
+ _revision_diff_ $old, $new, @$_ for(
[ hidden => 'Hidden', fmt => 'bool' ],
[ locked => 'Locked', fmt => 'bool' ],
@fields,
@@ -677,7 +678,7 @@ sub _revision_cmp_ {
# Revision info box.
#
-# Arguments: $type, $object, \&enrich_for_diff, @fields
+# Arguments: $object, \&enrich_for_diff, @fields
#
# The given $object is assumed to originate from VNWeb::DB::db_entry() and
# should have the 'id', 'hidden', 'locked', 'chrev' and 'maxrev' fields in
@@ -702,9 +703,9 @@ sub _revision_cmp_ {
# empty => str - What value should be considered "empty", e.g. (empty => 0) for integer fields.
# undef or empty string are always considered empty values.
sub revision_ {
- my($type, $new, $enrich, @fields) = @_;
+ my($new, $enrich, @fields) = @_;
- my $old = $new->{chrev} == 1 ? undef : db_entry $type, $new->{id}, $new->{chrev} - 1;
+ my $old = $new->{chrev} == 1 ? undef : db_entry $new->{id}, $new->{chrev} - 1;
$enrich->($old) if $old;
enrich_merge chid => sql(
@@ -716,19 +717,19 @@ sub revision_ {
div_ class => 'mainbox revision', sub {
h1_ "Revision $new->{chrev}";
- a_ class => 'prev', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{chrev}-1), '<- earlier revision' if $new->{chrev} > 1;
- a_ class => 'next', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{chrev}+1), 'later revision ->' if $new->{chrev} < $new->{maxrev};
- p_ class => 'center', sub { a_ href => "/$type$new->{id}", $type.$new->{id} };
+ a_ class => 'prev', href => sprintf('/%s.%d', $new->{id}, $new->{chrev}-1), '<- earlier revision' if $new->{chrev} > 1;
+ a_ class => 'next', href => sprintf('/%s.%d', $new->{id}, $new->{chrev}+1), 'later revision ->' if $new->{chrev} < $new->{maxrev};
+ p_ class => 'center', sub { a_ href => "/$new->{id}", $new->{id} };
div_ class => 'rev', sub {
- _revision_header_ $type, $new;
+ _revision_header_ $new;
br_;
b_ 'Edit summary';
br_; br_;
lit_ bb_format $new->{rev_comments}||'-';
} if !$old;
- _revision_cmp_ $type, $old, $new, @fields if $old;
+ _revision_cmp_ $old, $new, @fields if $old;
};
}
@@ -814,17 +815,16 @@ sub searchbox_ {
# Generate a message to display on an entry page to report the entry and to indicate it has been locked or the user can't edit it.
sub itemmsg_ {
- my($type, $obj) = @_;
+ my($obj) = @_;
p_ class => 'itemmsg', sub {
- if($type ne 'd' && $type ne 'w') {
+ if($obj->{id} !~ /^[dw]/) {
if($obj->{entry_locked}) {
txt_ 'Locked for editing. ';
- } elsif(auth && !can_edit $type => $obj) {
+ } elsif(auth && !can_edit(($obj->{id} =~ /^(.)/), $obj)) {
txt_ 'You can not edit this page. ';
}
}
- my $id = $obj->{id} =~ /^[0-9]*$/ ? "$type$obj->{id}" : $obj->{id};
- a_ href => "/report/$id", 'Report an issue on this page.';
+ a_ href => "/report/$obj->{id}", 'Report an issue on this page.';
};
}
@@ -848,7 +848,7 @@ sub editmsg_ {
h2_ "You're not editing an entry!";
p_ sub {;
txt_ "You're about to insert a new entry into the database with information based on ";
- a_ href => "/$type$obj->{id}", "$type$obj->{id}";
+ a_ href => "/$obj->{id}", $obj->{id};
txt_ '.';
br_;
txt_ "Hit the 'edit' tab on the right-top if you intended to edit the entry instead of creating a new one.";
@@ -878,7 +878,7 @@ sub editmsg_ {
# TODO: Include a list of the most recent edits in this page.
li_ sub {
txt_ 'Browse the ';
- a_ href => "/$type$obj->{id}/hist", 'edit history';
+ a_ href => "/$obj->{id}/hist", 'edit history';
txt_ ' for any recent changes related to what you want to change.';
};
} elsif($type ne 'r') {
diff --git a/lib/VNWeb/Images/Lib.pm b/lib/VNWeb/Images/Lib.pm
index 157b9679..25de1b13 100644
--- a/lib/VNWeb/Images/Lib.pm
+++ b/lib/VNWeb/Images/Lib.pm
@@ -25,7 +25,7 @@ sub enrich_image {
, i.c_violence_avg AS violence_avg, i.c_violence_stddev AS violence_stddev
, iv.sexual AS my_sexual, iv.violence AS my_violence
, COALESCE(EXISTS(SELECT 1 FROM image_votes iv0 WHERE iv0.id = i.id AND iv0.ignore) AND NOT iv.ignore, FALSE) AS my_overrule
- , COALESCE('v'||v.id, 'c'||c.id, 'v'||vsv.id) AS entry_id
+ , COALESCE(v.id, c.id, vsv.id) AS entry_id
, COALESCE(v.title, c.name, vsv.title) AS entry_title
FROM images i
LEFT JOIN image_votes iv ON iv.id = i.id AND iv.uid =}, \auth->uid, q{
diff --git a/lib/VNWeb/Images/List.pm b/lib/VNWeb/Images/List.pm
index 69925f99..132386b6 100644
--- a/lib/VNWeb/Images/List.pm
+++ b/lib/VNWeb/Images/List.pm
@@ -29,7 +29,7 @@ sub graph_ {
$y = 13;
line_ 'Avg', $avg-$stddev, $avg, $avg+$stddev if defined $avg;
line_ 'User', $user, $user, $avg if defined $user;
- line_ 'My', $my, $my, $avg if defined $my && $opt->{u} != $opt->{u2};
+ line_ 'My', $my, $my, $avg if defined $my && $opt->{u} ne $opt->{u2};
}
tag_ 'svg', width => '190px', height => '100px', viewBox => '0 0 190 100', sub {
@@ -76,7 +76,7 @@ sub opts_ {
form_ sub {
input_ type => 'hidden', class => 'hidden', name => 'u', value => $opt->{u} if $opt->{u};
- input_ type => 'hidden', class => 'hidden', name => 'u2', value => $opt->{u2} if $opt->{u2} != (auth->uid||0);
+ input_ type => 'hidden', class => 'hidden', name => 'u2', value => $opt->{u2} if $opt->{u2} ne (auth->uid||'');
input_ type => 'hidden', class => 'hidden', name => 'view', value => viewset(show_nsfw => viewget('show_nsfw'));
table_ style => 'margin: auto', sub {
tr_ sub {
@@ -98,7 +98,7 @@ sub opts_ {
tr_ sub {
td_ '';
td_ class => 'linkradio', sub { opt_ checkbox => my => 1, 'Only images I voted on' };
- } if auth && $opt->{u} != $opt->{u2};
+ } if auth && $opt->{u} ne $opt->{u2};
tr_ sub {
td_ 'Time filter';
td_ class => 'linkradio', sub {
@@ -136,13 +136,13 @@ TUWF::get qr{/img/list}, sub {
t => { onerror => [], scalar => 1, type => 'array', values => { enum => [qw/ ch cv sf /] } },
m => { onerror => 0, range => [0,10] },
d => { onerror => 0, range => [0,10000] },
- u => { onerror => 0, id => 1 },
- u2 => { onerror => 0, id => 1 }, # Hidden option, allows comparing two users by overriding the 'My' user.
+ u => { onerror => '', vndbid => 'u' },
+ u2 => { onerror => '', vndbid => 'u' }, # Hidden option, allows comparing two users by overriding the 'My' user.
my => { anybool => 1 },
p => { page => 1 },
)->data;
- $opt->{u2} ||= auth->uid || 0;
+ $opt->{u2} ||= auth->uid || '';
$opt->{s} = 'weight' if !$opt->{u} && ($opt->{s} eq 'date' || $opt->{s} eq 'diff');
$opt->{t} = [ List::Util::uniq sort $opt->{t}->@* ];
$opt->{t} = [] if $opt->{t}->@* == 3;
@@ -163,7 +163,7 @@ TUWF::get qr{/img/list}, sub {
$opt->{u} ? ', iu.sexual as user_sexual, iu.violence as user_violence' : (), '
FROM images i',
$opt->{u} ? ('JOIN image_votes iu ON iu.uid =', \$opt->{u}, ' AND iu.id = i.id') : (),
- $opt->{my} ? () : 'LEFT', 'JOIN image_votes iv ON iv.uid =', \$opt->{u2}, ' AND iv.id = i.id
+ $opt->{my} ? () : 'LEFT', 'JOIN image_votes iv ON iv.uid =', \($opt->{u2}||undef), ' AND iv.id = i.id
WHERE', $where, '
ORDER BY', {
weight => 'i.c_weight DESC',
diff --git a/lib/VNWeb/Images/Vote.pm b/lib/VNWeb/Images/Vote.pm
index aba0342f..ad320155 100644
--- a/lib/VNWeb/Images/Vote.pm
+++ b/lib/VNWeb/Images/Vote.pm
@@ -45,7 +45,7 @@ elm_api Images => $SEND, { excl_voted => { anybool => 1 } }, sub {
SELECT id
FROM images TABLESAMPLE SYSTEM (', \$tablesample, ')
WHERE c_weight > 0',
- $data->{excl_voted} ? ('AND NOT (c_uids && ARRAY[', \auth->uid, '::int])') : (), '
+ $data->{excl_voted} ? ('AND NOT (c_uids && ARRAY[', \auth->uid, '::vndbid])') : (), '
ORDER BY random() ^ (1.0/c_weight) DESC
LIMIT', \30
);
diff --git a/lib/VNWeb/Misc/Feeds.pm b/lib/VNWeb/Misc/Feeds.pm
index fdc6606c..ed58b37e 100644
--- a/lib/VNWeb/Misc/Feeds.pm
+++ b/lib/VNWeb/Misc/Feeds.pm
@@ -27,7 +27,7 @@ sub feed {
tag published => datetime $_->{published} if $_->{published};
tag author => sub {
tag name => $_->{user_name};
- tag uri => "$base/u$_->{user_id}";
+ tag uri => "$base/$_->{user_id}";
} if $_->{user_id};
tag link => rel => 'alternate', type => 'text/html', href => "$base/$_->{id}", undef;
tag summary => type => 'html', bb_format $_->{summary}, maxlength => 300 if $_->{summary};
@@ -52,9 +52,9 @@ TUWF::get qr{/feeds/announcements.atom}, sub {
TUWF::get qr{/feeds/changes.atom}, sub {
- my($lst) = VNWeb::Misc::History::fetch(undef, undef, {m=>1,h=>1,p=>1}, {results=>25});
+ my($lst) = VNWeb::Misc::History::fetch(undef, {m=>1,h=>1,p=>1}, {results=>25});
for (@$lst) {
- $_->{id} = "$_->{type}$_->{itemid}.$_->{rev}";
+ $_->{id} = "$_->{itemid}.$_->{rev}";
$_->{summary} = $_->{comments};
$_->{updated} = $_->{added};
}
diff --git a/lib/VNWeb/Misc/History.pm b/lib/VNWeb/Misc/History.pm
index cd94c28f..f8e15f27 100644
--- a/lib/VNWeb/Misc/History.pm
+++ b/lib/VNWeb/Misc/History.pm
@@ -5,32 +5,27 @@ use VNWeb::Prelude;
# Also used by Misc::HomePage and Misc::Feeds
sub fetch {
- my($type, $id, $filt, $opt) = @_;
+ my($id, $filt, $opt) = @_;
my $where = sql_and
- !$type ? ()
- : $type eq 'u' ? sql 'c.requester =', \$id
- : sql_or(
- sql('c.type =', \$type, ' AND c.itemid =', \$id),
+ !$id ? ()
+ : $id =~ /^u/ ? sql 'c.requester =', \$id
+ : $id =~ /^v/ && $filt->{r} ? sql 'c.itemid =', \$id, 'OR c.id IN(SELECT chid FROM releases_vn_hist WHERE vid =', \$id, ')' # This may need an index on releases_vn_hist.vid
+ : sql('c.itemid =', \$id),
- # This may need an index on releases_vn_hist.vid
- $type eq 'v' && $filt->{r} ?
- sql 'c.id IN(SELECT chid FROM releases_vn_hist WHERE vid =', \$id, ')' : ()
- ),
-
- $filt->{t} && $filt->{t}->@* ? sql 'c.type IN', \$filt->{t} : (),
- $filt->{m} ? sql 'c.requester IS DISTINCT FROM 1' : (),
+ $filt->{t} && $filt->{t}->@* ? sql_or map sql('c.itemid BETWEEN vndbid(', \"$_", ',1) AND vndbid_max(', \"$_", ')'), $filt->{t}->@* : (),
+ $filt->{m} ? sql 'c.requester IS DISTINCT FROM \'u1\'' : (),
$filt->{e} && $filt->{e} == 1 ? sql 'c.rev <> 1' : (),
$filt->{e} && $filt->{e} ==-1 ? sql 'c.rev = 1' : (),
$filt->{h} ? sql $filt->{h} == 1 ? 'NOT' : '',
'EXISTS(SELECT 1 FROM changes c_i
- WHERE c_i.type = c.type AND c_i.itemid = c.itemid AND c_i.ihid
- AND c_i.rev = (SELECT MAX(c_ii.rev) FROM changes c_ii WHERE c_ii.type = c.type AND c_ii.itemid = c.itemid))' : ();
+ WHERE c_i.itemid = c.itemid AND c_i.ihid
+ AND c_i.rev = (SELECT MAX(c_ii.rev) FROM changes c_ii WHERE c_ii.itemid = c.itemid))' : ();
my($lst, $np) = tuwf->dbPagei({ page => $filt->{p}, results => $opt->{results}||50 }, q{
- SELECT c.id, c.type, c.itemid, c.comments, c.rev,}, sql_totime('c.added'), q{ AS added, }, sql_user(), q{
+ SELECT c.id, c.itemid, c.comments, c.rev,}, sql_totime('c.added'), q{ AS added, }, sql_user(), q{
FROM changes c
LEFT JOIN users u ON c.requester = u.id
WHERE}, $where, q{
@@ -55,9 +50,9 @@ sub fetch {
# Also used by User::Page.
# %opt: nopage => 1/0, results => $num
sub tablebox_ {
- my($type, $id, $filt, %opt) = @_;
+ my($id, $filt, %opt) = @_;
- my($lst, $np) = fetch $type, $id, $filt, \%opt;
+ my($lst, $np) = fetch $id, $filt, \%opt;
my sub url { '?'.query_encode %$filt, p => $_ }
@@ -73,9 +68,9 @@ sub tablebox_ {
}};
tr_ sub {
my $i = $_;
- my $revurl = "/$i->{type}$i->{itemid}.$i->{rev}";
+ my $revurl = "/$i->{itemid}.$i->{rev}";
- td_ class => 'tc1_1', sub { a_ href => $revurl, "$i->{type}$i->{itemid}" };
+ td_ class => 'tc1_1', sub { a_ href => $revurl, $i->{itemid} };
td_ class => 'tc1_2', sub { a_ href => $revurl, ".$i->{rev}" };
td_ class => 'tc2', fmtdate $i->{added}, 'full';
td_ class => 'tc3', sub { user_ $i };
@@ -168,23 +163,21 @@ sub filters_ {
}
-TUWF::get qr{/(?:([upvrcsd])([1-9]\d*)/)?hist} => sub {
- my($type, $id) = (tuwf->capture(1)||'', tuwf->capture(2));
-
- my $obj = dbobj $type, $id;
+TUWF::get qr{/(?:([upvrcsd][1-9][0-9]{0,6})/)?hist} => sub {
+ my $id = tuwf->capture(1)||'';
+ my $obj = dbobj $id;
- return tuwf->resNotFound if $type && !$obj->{id};
- $obj->{title} = user_displayname $obj if $type eq 'u';
+ return tuwf->resNotFound if $id && !$obj->{id};
- my $title = $type ? "Edit history of $obj->{title}" : 'Recent changes';
- framework_ title => $title, type => $type, dbobj => $obj, tab => 'hist',
+ my $title = $id ? "Edit history of $obj->{title}" : 'Recent changes';
+ framework_ title => $title, dbobj => $obj, tab => 'hist',
sub {
my $filt;
div_ class => 'mainbox', sub {
h1_ $title;
- $filt = filters_ $type;
+ $filt = filters_($id =~ /^(.)/ or '');
};
- tablebox_ $type, $id, $filt;
+ tablebox_ $id, $filt;
};
};
diff --git a/lib/VNWeb/Misc/HomePage.pm b/lib/VNWeb/Misc/HomePage.pm
index bcf7052f..c591568a 100644
--- a/lib/VNWeb/Misc/HomePage.pm
+++ b/lib/VNWeb/Misc/HomePage.pm
@@ -32,7 +32,7 @@ sub screens_ {
);
p_ class => 'screenshots', sub {
- a_ href => "/v$_->{vid}", title => $_->{title}, sub {
+ a_ href => "/$_->{vid}", title => $_->{title}, sub {
my($w, $h) = imgsize $_->{width}, $_->{height}, config->{scr_size}->@*;
img_ src => imgurl($_->{id}, 1), alt => $_->{title}, width => $w, height => $h;
} for @$lst;
@@ -41,7 +41,7 @@ sub screens_ {
sub recent_changes_ {
- my($lst) = VNWeb::Misc::History::fetch(undef, undef, {m=>1,h=>1,p=>1}, {results=>10});
+ my($lst) = VNWeb::Misc::History::fetch(undef, {m=>1,h=>1,p=>1}, {results=>10});
h1_ sub {
a_ href => '/hist', 'Recent Changes'; txt_ ' ';
a_ href => '/feeds/changes.atom', sub { abbr_ class => 'icons feed', title => 'Atom Feed', '' };
@@ -49,8 +49,8 @@ sub recent_changes_ {
ul_ sub {
li_ sub {
span_ sub {
- txt_ "$_->{type}:";
- a_ href => "/$_->{type}$_->{itemid}.$_->{rev}", title => $_->{original}||$_->{title}, $_->{title};
+ txt_ "$1:" if $_->{itemid} =~ /^(.)/;
+ a_ href => "/$_->{itemid}.$_->{rev}", title => $_->{original}||$_->{title}, $_->{title};
};
span_ sub {
lit_ " by ";
@@ -192,7 +192,7 @@ sub releases_ {
abbr_ class => "icons $_", title => $PLATFORM{$_}, '' for $_->{plat}->@*;
abbr_ class => "icons lang $_", title => $LANGUAGE{$_}, '' for $_->{lang}->@*;
txt_ ' ';
- a_ href => "/r$_->{id}", title => $_->{original}||$_->{title}, $_->{title};
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{title}, $_->{title};
}
} for @$lst;
};
diff --git a/lib/VNWeb/Misc/Redirects.pm b/lib/VNWeb/Misc/Redirects.pm
index 636a766c..72ba7369 100644
--- a/lib/VNWeb/Misc/Redirects.pm
+++ b/lib/VNWeb/Misc/Redirects.pm
@@ -21,9 +21,9 @@ TUWF::get qr{/u/list(/[a-z0]|/all)?}, sub { tuwf->resRedirect('/u'.(tuwf->captur
TUWF::get qr{/$RE{uid}/tags}, sub { tuwf->resRedirect('/g/links?u='.tuwf->capture('id'), 'perm') };
-TUWF::get qr{/$RE{vid}/staff}, sub { tuwf->resRedirect(sprintf '/v%s#staff', tuwf->capture('id')) };
-TUWF::get qr{/$RE{vid}/stats}, sub { tuwf->resRedirect(sprintf '/v%s#stats', tuwf->capture('id')) };
-TUWF::get qr{/$RE{vid}/scr}, sub { tuwf->resRedirect(sprintf '/v%s#screenshots', tuwf->capture('id')) };
+TUWF::get qr{/$RE{vid}/staff}, sub { tuwf->resRedirect(sprintf '/%s#staff', tuwf->capture('id')) };
+TUWF::get qr{/$RE{vid}/stats}, sub { tuwf->resRedirect(sprintf '/%s#stats', tuwf->capture('id')) };
+TUWF::get qr{/$RE{vid}/scr}, sub { tuwf->resRedirect(sprintf '/%s#screenshots', tuwf->capture('id')) };
TUWF::get qr{/v/rand}, sub {
@@ -38,7 +38,7 @@ TUWF::get qr{/v/rand}, sub {
ORDER BY random() LIMIT 1'
);
return tuwf->resNotFound if !$vn;
- tuwf->resRedirect("/v$vn", 'temp');
+ tuwf->resRedirect("/$vn", 'temp');
};
1;
diff --git a/lib/VNWeb/Misc/Reports.pm b/lib/VNWeb/Misc/Reports.pm
index c275efa9..3697922f 100644
--- a/lib/VNWeb/Misc/Reports.pm
+++ b/lib/VNWeb/Misc/Reports.pm
@@ -48,13 +48,12 @@ sub enrich_object {
user_ $post;
} if $post->{num};
- } elsif($o->{object} =~ /^([vrpcsd])$RE{num}$/ && !defined $o->{objectnum}) {
- my($t,$id) = ($1, $+{num});
- my $obj = dbobj $t, $id;
+ } elsif($o->{object} =~ /^([vrpcsd]$RE{num})$/ && !defined $o->{objectnum}) {
+ my $obj = dbobj $1;
$o->{title} = xml_string sub {
- txt_ {qw/v VN r Release p Producer c Character s Staff d Doc/}->{$t};
+ txt_ {qw/v VN r Release p Producer c Character s Staff d Doc/}->{substr $obj->{id}, 0, 1};
txt_ ': ';
- a_ href => "/$t$id", $obj->{title};
+ a_ href => "/$obj->{id}", $obj->{title};
} if $obj->{id};
}
}
@@ -119,9 +118,9 @@ sub report_ {
b_ class => 'grayedout', ' '.fmtdate $r->{date}, 'full';
txt_ ' by ';
if($r->{uid}) {
- a_ href => "/u$r->{uid}", $r->{username};
+ a_ href => "/$r->{uid}", $r->{username};
txt_ ' (';
- a_ href => "/t/u$r->{uid}/new?title=Regarding your report on $objid&priv=1", 'pm';
+ a_ href => "/t/$r->{uid}/new?title=Regarding your report on $objid&priv=1", 'pm';
txt_ ')';
} else {
txt_ $r->{ip}||'[anonymous]';
diff --git a/lib/VNWeb/Prelude.pm b/lib/VNWeb/Prelude.pm
index ca7a423e..5a893232 100644
--- a/lib/VNWeb/Prelude.pm
+++ b/lib/VNWeb/Prelude.pm
@@ -71,80 +71,60 @@ sub import {
no strict 'refs';
*{$c.'::RE'} = *RE;
- *{$c.'::in'} = \&in;
- *{$c.'::idcmp'} = \&idcmp;
*{$c.'::dbobj'} = \&dbobj;
}
# Regular expressions for use in path registration
my $num = qr{[1-9][0-9]{0,6}}; # Allow up to 10 mil, SQL vndbid type can't handle more than 2^26-1 (~ 67 mil).
-my $id = qr{(?<id>$num)};
my $rev = qr{(?:\.(?<rev>$num))};
our %RE = (
num => qr{(?<num>$num)},
- uid => qr{u$id},
- vid => qr{v$id},
- rid => qr{r$id},
- sid => qr{s$id},
- cid => qr{c$id},
- pid => qr{p$id},
- iid => qr{i$id},
- did => qr{d$id},
+ uid => qr{(?<id>u$num)},
+ vid => qr{(?<id>v$num)},
+ rid => qr{(?<id>r$num)},
+ sid => qr{(?<id>s$num)},
+ cid => qr{(?<id>c$num)},
+ pid => qr{(?<id>p$num)},
+ iid => qr{i(?<id>$num)},
+ did => qr{(?<id>d$num)},
tid => qr{(?<id>t$num)},
- gid => qr{g$id},
+ gid => qr{g(?<id>$num)},
wid => qr{(?<id>w$num)},
imgid=> qr{(?<id>(?:ch|cv|sf)$num)},
- vrev => qr{v$id$rev?},
- rrev => qr{r$id$rev?},
- prev => qr{p$id$rev?},
- srev => qr{s$id$rev?},
- crev => qr{c$id$rev?},
- drev => qr{d$id$rev?},
+ vrev => qr{(?<id>v$num)$rev?},
+ rrev => qr{(?<id>r$num)$rev?},
+ prev => qr{(?<id>p$num)$rev?},
+ srev => qr{(?<id>s$num)$rev?},
+ crev => qr{(?<id>c$num)$rev?},
+ drev => qr{(?<id>d$num)$rev?},
postid => qr{(?<id>t$num)\.(?<num>$num)},
);
-# Simple "is this element in the array?" function, using 'eq' to test equality.
-# Supports both an @array and \@array.
-# Usage:
-#
-# my $contains_hi = in 'hi', qw/ a b hi c /; # true
-#
-sub in {
- my($q, @a) = @_;
- $_ eq $q && return 1 for map ref $_ eq 'ARRAY' ? @$_ : ($_), @a;
- 0
-}
-
-
-# Compare two vndbids, using proper numeric order
-sub idcmp($$) {
- my($a1, $a2) = $_[0] =~ /^([a-z]+)([0-9]+)$/;
- my($b1, $b2) = $_[1] =~ /^([a-z]+)([0-9]+)$/;
- $a1 cmp $b1 || $a2 <=> $b2
-}
-
-
# Returns very generic information on a DB entry object.
# Only { id, title, entry_hidden, entry_locked } for now.
# Suitable for passing to HTML::framework_'s dbobj argument.
+# TODO: Merge with SQL's item_info() or something.
sub dbobj {
- my($type, $id) = @_;
+ my($id) = @_;
my sub item {
my($table, $title) = @_;
tuwf->dbRowi('SELECT id,', $title, ' AS title, hidden AS entry_hidden, locked AS entry_locked FROM', $table, 'WHERE id =', \$id);
};
- !$type ? undef :
- $type eq 'u' ? tuwf->dbRowi('SELECT id, ', sql_user(), 'FROM users u WHERE id =', \$id) :
- $type eq 'p' ? item producers => 'name' :
- $type eq 'v' ? item vn => 'title' :
- $type eq 'r' ? item releases => 'title' :
- $type eq 'c' ? item chars => 'name' :
- $type eq 's' ? item staff => '(SELECT name FROM staff_alias WHERE aid = staff.aid)' :
- $type eq 'd' ? item docs => 'title' : die;
+ my $o = !$id ? undef :
+ $id =~ /^u/ ? tuwf->dbRowi('SELECT id, ', sql_user(), 'FROM users u WHERE id =', \$id) :
+ $id =~ /^p/ ? item producers => 'name' :
+ $id =~ /^v/ ? item vn => 'title' :
+ $id =~ /^r/ ? item releases => 'title' :
+ $id =~ /^c/ ? item chars => 'name' :
+ $id =~ /^s/ ? item staff => '(SELECT name FROM staff_alias WHERE aid = staff.aid)' :
+ $id =~ /^d/ ? item docs => 'title' : die;
+
+ $o->{title} = VNWeb::HTML::user_displayname $o if $id =~ /^u/;
+ $o;
}
1;
diff --git a/lib/VNWeb/Producers/Edit.pm b/lib/VNWeb/Producers/Edit.pm
index 0a5df222..fbd14e5f 100644
--- a/lib/VNWeb/Producers/Edit.pm
+++ b/lib/VNWeb/Producers/Edit.pm
@@ -4,7 +4,7 @@ use VNWeb::Prelude;
my $FORM = {
- id => { required => 0, id => 1 },
+ id => { required => 0, vndbid => 'p' },
ptype => { default => 'co', enum => \%PRODUCER_TYPE },
name => { maxlength => 200 },
original => { required => 0, default => '', maxlength => 200 },
@@ -14,7 +14,7 @@ my $FORM = {
l_wikidata => { required => 0, uint => 1, max => (1<<31)-1 },
desc => { required => 0, default => '', maxlength => 5000 },
relations => { sort_keys => 'pid', aoh => {
- pid => { id => 1 },
+ pid => { vndbid => 'p' },
relation => { enum => \%PRODUCER_RELATION },
name => { _when => 'out' },
original => { _when => 'out', required => 0, default => '' },
@@ -32,16 +32,16 @@ my $FORM_CMP = form_compile cmp => $FORM;
TUWF::get qr{/$RE{prev}/edit} => sub {
- my $e = db_entry p => tuwf->capture('id'), tuwf->capture('rev') or return tuwf->resNotFound;
+ my $e = db_entry tuwf->captures('id', 'rev') or return tuwf->resNotFound;
return tuwf->resDenied if !can_edit p => $e;
$e->{authmod} = auth->permDbmod;
- $e->{editsum} = $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision p$e->{id}.$e->{chrev}";
+ $e->{editsum} = $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision $e->{id}.$e->{chrev}";
$e->{ptype} = delete $e->{type};
enrich_merge pid => 'SELECT id AS pid, name, original FROM producers WHERE id IN', $e->{relations};
- framework_ title => "Edit $e->{name}", type => 'p', dbobj => $e, tab => 'edit',
+ framework_ title => "Edit $e->{name}", dbobj => $e, tab => 'edit',
sub {
editmsg_ p => $e, "Edit $e->{name}";
elm_ ProducerEdit => $FORM_OUT, $e;
@@ -63,7 +63,7 @@ TUWF::get qr{/p/add}, sub {
elm_api ProducerEdit => $FORM_OUT, $FORM_IN, sub {
my $data = shift;
my $new = !$data->{id};
- my $e = $new ? { id => 0 } : db_entry p => $data->{id} or return tuwf->resNotFound;
+ my $e = $new ? { id => 0 } : db_entry $data->{id} or return tuwf->resNotFound;
return elm_Unauth if !can_edit p => $e;
if(!auth->permDbmod) {
@@ -75,14 +75,14 @@ elm_api ProducerEdit => $FORM_OUT, $FORM_IN, sub {
$data->{relations} = [] if $data->{hidden};
validate_dbid 'SELECT id FROM producers WHERE id IN', map $_->{pid}, $data->{relations}->@*;
- die "Relation with self" if grep $_->{pid} == $e->{id}, $data->{relations}->@*;
+ die "Relation with self" if grep $_->{pid} eq $e->{id}, $data->{relations}->@*;
$e->{ptype} = $e->{type};
$data->{type} = $data->{ptype};
return elm_Unchanged if !$new && !form_changed $FORM_CMP, $data, $e;
- my($id,undef,$rev) = db_edit p => $e->{id}, $data;
- update_reverse($id, $rev, $e, $data);
- elm_Redirect "/p$id.$rev";
+ my $ch = db_edit p => $e->{id}, $data;
+ update_reverse($ch->{nitemid}, $ch->{nrev}, $e, $data);
+ elm_Redirect "/$ch->{nitemid}.$ch->{nrev}";
};
@@ -107,13 +107,13 @@ sub update_reverse {
}
for my $i (keys %upd) {
- my $e = db_entry p => $i;
+ my $e = db_entry $i;
$e->{relations} = [
$upd{$i} ? $upd{$i} : (),
- grep $_->{pid} != $id, $e->{relations}->@*
+ grep $_->{pid} ne $id, $e->{relations}->@*
];
- $e->{editsum} = "Reverse relation update caused by revision p$id.$rev";
- db_edit p => $i, $e, 1;
+ $e->{editsum} = "Reverse relation update caused by revision $id.$rev";
+ db_edit p => $i, $e, 'u1';
}
}
diff --git a/lib/VNWeb/Producers/Graph.pm b/lib/VNWeb/Producers/Graph.pm
index 66f7e63c..005a2492 100644
--- a/lib/VNWeb/Producers/Graph.pm
+++ b/lib/VNWeb/Producers/Graph.pm
@@ -29,18 +29,18 @@ TUWF::get qr{/$RE{pid}/rg}, sub {
my @lines;
my $params = $num == 15 ? '' : "?num=$num";
- for my $n (sort { $a->{id} <=> $b->{id} } values %$nodes) {
+ for my $n (sort { idcmp $a->{id}, $b->{id} } values %$nodes) {
my $name = val_escape shorten $n->{name}, 27;
my $tooltip = val_escape $n->{name};
my $nodeid = $n->{distance} == 0 ? 'id = "graph_current", ' : '';
push @lines,
- qq|n$n->{id} [ $nodeid URL = "/p$n->{id}", tooltip = "$tooltip", label=<|.
+ qq|n$n->{id} [ $nodeid URL = "/$n->{id}", tooltip = "$tooltip", label=<|.
qq|<TABLE CELLSPACING="0" CELLPADDING="2" BORDER="0" CELLBORDER="1" BGCOLOR="#222222">|.
qq|<TR><TD COLSPAN="2" ALIGN="CENTER" CELLPADDING="3"><FONT POINT-SIZE="9"> $name </FONT></TD></TR>|.
qq|<TR><TD ALIGN="CENTER"> $LANGUAGE{$n->{lang}} </TD><TD ALIGN="CENTER"> $PRODUCER_TYPE{$n->{type}} </TD></TR>|.
qq|</TABLE>> ]|;
- push @lines, node_more $n->{id}, "/p$n->{id}/rg$params", scalar grep !$nodes->{$_}, $n->{rels}->@*;
+ push @lines, node_more $n->{id}, "/$n->{id}/rg$params", scalar grep !$nodes->{$_}, $n->{rels}->@*;
}
$rel = [ grep $nodes->{$_->{id0}} && $nodes->{$_->{id1}}, @$rel ];
@@ -59,7 +59,7 @@ TUWF::get qr{/$RE{pid}/rg}, sub {
if($_ == min $num, $total_nodes) {
txt_ $_ ;
} else {
- a_ href => "/p$id/rg?num=$_", $_;
+ a_ href => "/$id/rg?num=$_", $_;
}
}, grep($_ < $total_nodes, 10, 15, 25, 50, 75, 100, 150, 250, 500, 750, 1000), $total_nodes;
txt_ '.';
diff --git a/lib/VNWeb/Producers/List.pm b/lib/VNWeb/Producers/List.pm
index bd301aaf..d6193ed5 100644
--- a/lib/VNWeb/Producers/List.pm
+++ b/lib/VNWeb/Producers/List.pm
@@ -17,7 +17,7 @@ sub listing_ {
ul_ sub {
li_ sub {
abbr_ class => "icons lang $_->{lang}", title => $LANGUAGE{$_->{lang}}, '';
- a_ href => "/p$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
} for @$list;
}
}
diff --git a/lib/VNWeb/Producers/Page.pm b/lib/VNWeb/Producers/Page.pm
index ee494518..f95c7489 100644
--- a/lib/VNWeb/Producers/Page.pm
+++ b/lib/VNWeb/Producers/Page.pm
@@ -14,7 +14,7 @@ sub enrich_item {
sub rev_ {
my($p) = @_;
- revision_ p => $p, \&enrich_item,
+ revision_ $p, \&enrich_item,
[ name => 'Name' ],
[ original => 'Original name' ],
[ alias => 'Aliases' ],
@@ -23,7 +23,7 @@ sub rev_ {
[ lang => 'Language', fmt => \%LANGUAGE ],
[ relations => 'Relations', fmt => sub {
txt_ $PRODUCER_RELATION{$_->{relation}}{txt}.': ';
- a_ href => "/p$_->{pid}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{pid}", title => $_->{original}||$_->{name}, $_->{name};
} ],
revision_extlinks 'p'
}
@@ -54,7 +54,7 @@ sub info_ {
join_ \&br_, sub {
txt_ $PRODUCER_RELATION{$_}{txt}.': ';
join_ ', ', sub {
- a_ href => "/p$_->{pid}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{pid}", title => $_->{original}||$_->{name}, $_->{name};
}, $rel{$_}->@*;
}, grep $rel{$_}, keys %PRODUCER_RELATION;
} if $p->{relations}->@*;
@@ -98,7 +98,7 @@ sub rel_ {
tr_ class => 'vn', sub {
# TODO: VN list status & management
td_ colspan => 8, sub {
- a_ href => "/v$v->{id}", title => $v->{original}||$v->{title}, $v->{title};
+ a_ href => "/$v->{id}", title => $v->{original}||$v->{title}, $v->{title};
};
my $ropt = { id => $v->{id}, prod => 1, lang => 1 };
release_row_ $_, $ropt for $vn{$v->{id}}->@*;
@@ -133,7 +133,7 @@ sub vns_ {
ul_ class => 'prodvns', sub {
li_ sub {
span_ sub { rdate_ $_->{released} };
- a_ href => "/v$_->{id}", title => $_->{original}||$_->{title}, $_->{title};
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{title}, $_->{title};
span_ join ' & ',
$_->{publisher} ? 'Publisher' : (),
$_->{developer} ? 'Developer' : ();
@@ -144,7 +144,7 @@ sub vns_ {
TUWF::get qr{/$RE{prev}(?:/(?<tab>vn|rel))?}, sub {
- my $p = db_entry p => tuwf->capture('id'), tuwf->capture('rev');
+ my $p = db_entry tuwf->captures('id', 'rev');
return tuwf->resNotFound if !$p;
enrich_item $p;
@@ -153,7 +153,7 @@ TUWF::get qr{/$RE{prev}(?:/(?<tab>vn|rel))?}, sub {
tuwf->resCookie(prodrelexpand => $tab eq 'vn' ? 1 : undef, expires => time + 315360000) if $tab && $tab ne $pref;
$tab = 'rel' if !$tab;
- framework_ title => $p->{name}, index => !tuwf->capture('rev'), type => 'p', dbobj => $p, hiddenmsg => 1,
+ framework_ title => $p->{name}, index => !tuwf->capture('rev'), dbobj => $p, hiddenmsg => 1,
og => {
title => $p->{name},
description => bb_format($p->{desc}, text => 1),
@@ -161,13 +161,13 @@ TUWF::get qr{/$RE{prev}(?:/(?<tab>vn|rel))?}, sub {
sub {
rev_ $p if tuwf->capture('rev');
div_ class => 'mainbox', sub {
- itemmsg_ p => $p;
+ itemmsg_ $p;
info_ $p;
};
div_ class => 'maintabs right', sub {
ul_ sub {
- li_ mkclass(tabselected => $tab eq 'vn'), sub { a_ href => "/p$p->{id}/vn", 'Visual Novels' };
- li_ mkclass(tabselected => $tab eq 'rel'), sub { a_ href => "/p$p->{id}/rel", 'Releases' };
+ li_ mkclass(tabselected => $tab eq 'vn'), sub { a_ href => "/$p->{id}/vn", 'Visual Novels' };
+ li_ mkclass(tabselected => $tab eq 'rel'), sub { a_ href => "/$p->{id}/rel", 'Releases' };
};
};
div_ class => 'mainbox', sub { rel_ $p } if $tab eq 'rel';
diff --git a/lib/VNWeb/Releases/Edit.pm b/lib/VNWeb/Releases/Edit.pm
index 839c42c5..fe6de7b9 100644
--- a/lib/VNWeb/Releases/Edit.pm
+++ b/lib/VNWeb/Releases/Edit.pm
@@ -4,7 +4,7 @@ use VNWeb::Prelude;
my $FORM = {
- id => { required => 0, id => 1 },
+ id => { required => 0, vndbid => 'r' },
title => { maxlength => 300 },
original => { required => 0, default => '', maxlength => 250 },
rtype => { default => 'complete', enum => \%RELEASE_TYPE },
@@ -33,11 +33,11 @@ my $FORM = {
extlinks => validate_extlinks('r'),
notes => { required => 0, default => '', maxlength => 10240 },
vn => { sort_keys => 'vid', aoh => {
- vid => { id => 1 },
+ vid => { vndbid => 'v' },
title => { _when => 'out' },
} },
producers => { sort_keys => 'pid', aoh => {
- pid => { id => 1 },
+ pid => { vndbid => 'p' },
developer => { anybool => 1 },
publisher => { anybool => 1 },
name => { _when => 'out' },
@@ -57,12 +57,12 @@ sub to_extlinks { $_[0]{extlinks} = { map +($_, delete $_[0]{$_}), grep /^l_/, k
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 $e = db_entry tuwf->captures('id', 'rev') or return tuwf->resNotFound;
my $copy = tuwf->capture('action') eq 'copy';
return tuwf->resDenied if !can_edit r => $copy ? {} : $e;
$e->{rtype} = delete $e->{type};
- $e->{editsum} = $copy ? "Copied from r$e->{id}.$e->{chrev}" : $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision r$e->{id}.$e->{chrev}";
+ $e->{editsum} = $copy ? "Copied from $e->{id}.$e->{chrev}" : $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision $e->{id}.$e->{chrev}";
$e->{authmod} = auth->permDbmod;
to_extlinks $e;
@@ -73,7 +73,7 @@ TUWF::get qr{/$RE{rrev}/(?<action>edit|copy)} => sub {
$e->@{qw/gtin catalog extlinks/} = elm_empty($FORM_OUT)->@{qw/gtin catalog extlinks/} if $copy;
my $title = ($copy ? 'Copy ' : 'Edit ').$e->{title};
- framework_ title => $title, type => 'r', dbobj => $e, tab => tuwf->capture('action'),
+ framework_ title => $title, dbobj => $e, tab => tuwf->capture('action'),
sub {
editmsg_ r => $e, $title, $copy;
elm_ ReleaseEdit => $FORM_OUT, $copy ? {%$e, id=>undef} : $e;
@@ -111,8 +111,8 @@ TUWF::get qr{/$RE{vid}/add}, sub {
br_;
ul_ sub {
li_ sub {
- txt_ '['.join(',', $_->{languages}->@*)."] r$_->{id}:";
- a_ href => "/r$_->{id}", title => $_->{original}||$_->{title}, $_->{title};
+ txt_ '['.join(',', $_->{languages}->@*)."] $_->{id}:";
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{title}, $_->{title};
} for @$delrel;
}
}
@@ -126,7 +126,7 @@ TUWF::get qr{/$RE{vid}/add}, sub {
elm_api ReleaseEdit => $FORM_OUT, $FORM_IN, sub {
my $data = shift;
my $new = !$data->{id};
- my $e = $new ? { id => 0 } : db_entry r => $data->{id} or return tuwf->resNotFound;
+ my $e = $new ? { id => 0 } : db_entry $data->{id} or return tuwf->resNotFound;
return elm_Unauth if !can_edit r => $e;
if(!auth->permDbmod) {
@@ -151,8 +151,8 @@ elm_api ReleaseEdit => $FORM_OUT, $FORM_IN, sub {
delete $data->{extlinks};
$data->{type} = delete $data->{rtype};
- my($id,undef,$rev) = db_edit r => $e->{id}, $data;
- elm_Redirect "/r$id.$rev";
+ my $ch = db_edit r => $e->{id}, $data;
+ elm_Redirect "/$ch->{nitemid}.$ch->{nrev}";
};
diff --git a/lib/VNWeb/Releases/Elm.pm b/lib/VNWeb/Releases/Elm.pm
index 40e6bfad..09c9ede2 100644
--- a/lib/VNWeb/Releases/Elm.pm
+++ b/lib/VNWeb/Releases/Elm.pm
@@ -5,7 +5,7 @@ use VNWeb::Releases::Lib;
# Used by UList.Opt and CharEdit to fetch releases from a VN id.
-elm_api Release => undef, { vid => { id => 1 } }, sub {
+elm_api Release => undef, { vid => { vndbid => 'v' } }, sub {
my($data) = @_;
elm_Releases releases_by_vn $data->{vid};
};
diff --git a/lib/VNWeb/Releases/Lib.pm b/lib/VNWeb/Releases/Lib.pm
index 07bb6878..3c97d326 100644
--- a/lib/VNWeb/Releases/Lib.pm
+++ b/lib/VNWeb/Releases/Lib.pm
@@ -113,7 +113,7 @@ sub release_row_ {
abbr_ class => "icons rt$r->{type}", title => $r->{type}, '';
};
td_ class => 'tc4', sub {
- a_ href => "/r$r->{id}", title => $r->{original}||$r->{title}, $r->{title};
+ a_ href => "/$r->{id}", title => $r->{original}||$r->{title}, $r->{title};
my $note = join ' ', $r->{official} ? () : 'unofficial', $r->{patch} ? 'patch' : ();
b_ class => 'grayedout', " ($note)" if $note;
};
diff --git a/lib/VNWeb/Releases/Page.pm b/lib/VNWeb/Releases/Page.pm
index 8067de7c..3d97dfe5 100644
--- a/lib/VNWeb/Releases/Page.pm
+++ b/lib/VNWeb/Releases/Page.pm
@@ -21,8 +21,8 @@ sub enrich_item {
sub _rev_ {
my($r) = @_;
- revision_ r => $r, \&enrich_item,
- [ vn => 'Relations', fmt => sub { a_ href => "/v$_->{vid}", title => $_->{original}||$_->{title}, $_->{title} } ],
+ revision_ $r, \&enrich_item,
+ [ vn => 'Relations', fmt => sub { a_ href => "/$_->{vid}", title => $_->{original}||$_->{title}, $_->{title} } ],
[ type => 'Type' ],
[ official => 'Official', fmt => 'bool' ],
[ patch => 'Patch', fmt => 'bool' ],
@@ -45,7 +45,7 @@ sub _rev_ {
[ ani_ero => 'Ero animation', fmt => \%ANIMATED ],
[ engine => 'Engine' ],
[ producers => 'Producers', fmt => sub {
- a_ href => "/p$_->{pid}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{pid}", title => $_->{original}||$_->{name}, $_->{name};
txt_ ' (';
txt_ join ', ', $_->{developer} ? 'developer' : (), $_->{publisher} ? 'publisher' : ();
txt_ ')';
@@ -62,7 +62,7 @@ sub _infotable_ {
td_ class => 'key', 'Relation';
td_ sub {
join_ \&br_, sub {
- a_ href => "/v$_->{vid}", title => $_->{original}||$_->{title}, $_->{title};
+ a_ href => "/$_->{vid}", title => $_->{original}||$_->{title}, $_->{title};
}, $r->{vn}->@*
}
};
@@ -168,7 +168,7 @@ sub _infotable_ {
td_ ucfirst($t).(@prod == 1 ? '' : 's');
td_ sub {
join_ \&br_, sub {
- a_ href => "/p$_->{pid}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{pid}", title => $_->{original}||$_->{name}, $_->{name};
}, @prod
}
} if @prod;
@@ -205,20 +205,20 @@ sub _infotable_ {
TUWF::get qr{/$RE{rrev}} => sub {
- my $r = db_entry r => tuwf->capture('id'), tuwf->capture('rev');
+ my $r = db_entry tuwf->captures('id','rev');
return tuwf->resNotFound if !$r;
enrich_item $r;
enrich_extlinks r => $r;
- framework_ title => $r->{title}, index => !tuwf->capture('rev'), type => 'r', dbobj => $r, hiddenmsg => 1,
+ framework_ title => $r->{title}, index => !tuwf->capture('rev'), dbobj => $r, hiddenmsg => 1,
og => {
description => bb_format $r->{notes}, text => 1
},
sub {
_rev_ $r if tuwf->capture('rev');
div_ class => 'mainbox release', sub {
- itemmsg_ r => $r;
+ itemmsg_ $r;
h1_ sub { txt_ $r->{title}; debug_ $r };
h2_ class => 'alttitle', lang_attr($r->{lang}), $r->{original} if length $r->{original};
_infotable_ $r;
diff --git a/lib/VNWeb/Releases/VNTab.pm b/lib/VNWeb/Releases/VNTab.pm
index 0c326402..e3da0609 100644
--- a/lib/VNWeb/Releases/VNTab.pm
+++ b/lib/VNWeb/Releases/VNTab.pm
@@ -30,7 +30,7 @@ my @rel_cols = (
sort_field => 'title',
sort_sql => 'r.title %s, r.released %1$s',
column_string => 'Title',
- draw => sub { a_ href => "/r$_[0]{id}", $_[0]{title} },
+ draw => sub { a_ href => "/$_[0]{id}", $_[0]{title} },
}, { # Type
id => 'typ',
sort_field => 'type',
@@ -221,7 +221,7 @@ sub listing_ {
TUWF::get qr{/$RE{vid}/releases} => sub {
- my $v = dbobj v => tuwf->capture('id');
+ my $v = dbobj tuwf->capture('id');
return tuwf->resNotFound if !$v->{id};
my $opt = tuwf->validate(get =>
diff --git a/lib/VNWeb/Reviews/Edit.pm b/lib/VNWeb/Reviews/Edit.pm
index 0ae4e652..d98b4e42 100644
--- a/lib/VNWeb/Reviews/Edit.pm
+++ b/lib/VNWeb/Reviews/Edit.pm
@@ -6,9 +6,9 @@ use VNWeb::Releases::Lib;
my $FORM = {
id => { vndbid => 'w', required => 0 },
- vid => { id => 1 },
+ vid => { vndbid => 'v' },
vntitle => { _when => 'out' },
- rid => { id => 1, required => 0 },
+ rid => { vndbid => 'r', required => 0 },
spoiler => { anybool => 1 },
isfull => { anybool => 1 },
text => { maxlength => 100_000, required => 0, default => '' },
@@ -58,7 +58,7 @@ TUWF::get qr{/$RE{wid}/edit}, sub {
$e->{releases} = releases_by_vn $e->{vid};
$e->{mod} = auth->permBoardmod;
- framework_ title => "Edit review for $e->{vntitle}", type => 'w', dbobj => $e, tab => 'edit', sub {
+ framework_ title => "Edit review for $e->{vntitle}", dbobj => $e, tab => 'edit', sub {
elm_ 'Reviews.Edit' => $FORM_OUT, $e;
};
};
@@ -83,7 +83,7 @@ elm_api ReviewsEdit => $FORM_OUT, $FORM_IN, sub {
if($id) {
$data->{lastmod} = sql 'NOW()';
tuwf->dbExeci('UPDATE reviews SET', $data, 'WHERE id =', \$id) if $id;
- auth->audit($review->{user_id}, 'review edit', "edited $review->{id}") if auth->uid != $review->{user_id};
+ auth->audit($review->{user_id}, 'review edit', "edited $review->{id}") if auth->uid ne $review->{user_id};
} else {
return elm_Unauth if tuwf->dbVali('SELECT 1 FROM reviews WHERE vid =', \$data->{vid}, 'AND uid =', \auth->uid);
diff --git a/lib/VNWeb/Reviews/List.pm b/lib/VNWeb/Reviews/List.pm
index eed0abf9..bb65c75b 100644
--- a/lib/VNWeb/Reviews/List.pm
+++ b/lib/VNWeb/Reviews/List.pm
@@ -46,7 +46,7 @@ TUWF::get qr{/w}, sub {
p => { page => 1 },
s => { onerror => 'id', enum => [qw[id lastpost rating]] },
o => { onerror => 'd', enum => [qw[a d]] },
- u => { onerror => 0, id => 1 },
+ u => { onerror => 0, vndbid => 'u' },
)->data;
$opt->{s} = 'id' if $opt->{s} eq 'rating' && !auth->isMod;
@@ -70,13 +70,13 @@ TUWF::get qr{/w}, sub {
);
my $title = $u ? 'Reviews by '.user_displayname($u) : 'Browse reviews';
- framework_ title => $title, $u ? (type => 'u', dbobj => $u, tab => 'reviews') : (), sub {
+ framework_ title => $title, $u ? (dbobj => $u, tab => 'reviews') : (), sub {
div_ class => 'mainbox', sub {
h1_ $title;
if($u && !$count) {
- p_ +(auth && $u->{id} == auth->uid ? 'You have' : user_displayname($u).' has').' not submitted any reviews yet.';
+ p_ +(auth && $u->{id} eq auth->uid ? 'You have' : user_displayname($u).' has').' not submitted any reviews yet.';
}
- p_ 'Note: The score column is only visible to moderators.' if auth->isMod;
+ p_ 'Note: The score column is only visible to moderators.' if $count && auth->isMod;
};
tablebox_ $opt, $lst, $count if $count;
};
diff --git a/lib/VNWeb/Reviews/Page.pm b/lib/VNWeb/Reviews/Page.pm
index 83a0755c..72b3b8d0 100644
--- a/lib/VNWeb/Reviews/Page.pm
+++ b/lib/VNWeb/Reviews/Page.pm
@@ -33,13 +33,13 @@ sub review_ {
tr_ sub {
td_ 'Subject';
td_ sub {
- a_ href => "/v$w->{vid}", $w->{title};
+ a_ href => "/$w->{vid}", $w->{title};
if($w->{rid}) {
br_;
abbr_ class => "icons $_", title => $PLATFORM{$_}, '' for grep $_ ne 'oth', $w->{platforms}->@*;
abbr_ class => "icons lang $_", title => $LANGUAGE{$_}, '' for $w->{lang}->@*;
abbr_ class => "icons rt$w->{rtype}", title => $w->{rtype}, '';
- a_ href => "/r$w->{rid}", title => $w->{roriginal}||$w->{rtitle}, $w->{rtitle};
+ a_ href => "/$w->{rid}", title => $w->{roriginal}||$w->{rtitle}, $w->{rtitle};
}
};
};
@@ -126,14 +126,14 @@ TUWF::get qr{/$RE{wid}(?:(?<sep>[\./])$RE{num})?}, sub {
auth->notiRead($id, undef);
auth->notiRead($id, [ map $_->{num}, $posts->@* ]) if @$posts;
- my $newreview = auth && auth->uid == $w->{user_id} && tuwf->reqGet('submit');
+ my $newreview = auth && auth->uid eq $w->{user_id} && tuwf->reqGet('submit');
my $title = "Review of $w->{title}";
- framework_ title => $title, index => 1, type => 'w', dbobj => $w,
+ framework_ title => $title, index => 1, dbobj => $w,
$num||$page>1 ? (pagevars => {sethash=>$num?$num:'threadstart'}) : (),
sub {
div_ class => 'mainbox', sub {
- itemmsg_ w => $w;
+ itemmsg_ $w;
h1_ $title;
div_ class => 'notice', sub {
b_ 'Review has been successfully submitted! ';
diff --git a/lib/VNWeb/Reviews/VNTab.pm b/lib/VNWeb/Reviews/VNTab.pm
index b2120e18..aa2949ec 100644
--- a/lib/VNWeb/Reviews/VNTab.pm
+++ b/lib/VNWeb/Reviews/VNTab.pm
@@ -32,7 +32,7 @@ sub reviews_ {
txt_ 'By '; user_ $r; txt_ ' on '.fmtdate $r->{date}, 'compact';
b_ class => 'grayedout', ' contains spoilers' if $r->{spoiler} && (auth->pref('spoilers')||0) == 2;
};
- a_ href => "/r$r->{rid}", "r$r->{rid}" if $r->{rid};
+ a_ href => "/$r->{rid}", $r->{rid} if $r->{rid};
span_ "Vote: ".fmtvote($r->{vote}) if $r->{vote};
};
div_ sub {
@@ -69,11 +69,11 @@ sub reviews_ {
TUWF::get qr{/$RE{vid}/(?<mini>mini|full)?reviews}, sub {
my $mini = !tuwf->capture('mini') ? undef : tuwf->capture('mini') eq 'mini' ? 1 : 0;
- my $v = db_entry v => tuwf->capture('id');
+ my $v = db_entry tuwf->capture('id');
return tuwf->resNotFound if !$v;
VNWeb::VN::Page::enrich_vn($v);
- framework_ title => ($mini?'Mini reviews':'Reviews')." for $v->{title}", index => 1, type => 'v', dbobj => $v, hiddenmsg => 1,
+ framework_ title => ($mini?'Mini reviews':'Reviews')." for $v->{title}", index => 1, dbobj => $v, hiddenmsg => 1,
sub {
VNWeb::VN::Page::infobox_($v);
VNWeb::VN::Page::tabs_($v, !defined $mini ? 'reviews' : $mini ? 'minireviews' : 'fullreviews');
diff --git a/lib/VNWeb/Staff/Edit.pm b/lib/VNWeb/Staff/Edit.pm
index 98b90d9f..24311d89 100644
--- a/lib/VNWeb/Staff/Edit.pm
+++ b/lib/VNWeb/Staff/Edit.pm
@@ -4,7 +4,7 @@ use VNWeb::Prelude;
my $FORM = {
- id => { required => 0, id => 1 },
+ id => { required => 0, vndbid => 's' },
aid => { int => 1, range => [ -1000, 1<<40 ] }, # X
alias => { maxlength => 100, sort_keys => 'aid', aoh => {
aid => { int => 1, range => [ -1000, 1<<40 ] }, # X, negative IDs are for new aliases
@@ -34,11 +34,11 @@ my $FORM_CMP = form_compile cmp => $FORM;
TUWF::get qr{/$RE{srev}/edit} => sub {
- my $e = db_entry s => tuwf->capture('id'), tuwf->capture('rev') or return tuwf->resNotFound;
+ my $e = db_entry tuwf->captures('id', 'rev') or return tuwf->resNotFound;
return tuwf->resDenied if !can_edit s => $e;
$e->{authmod} = auth->permDbmod;
- $e->{editsum} = $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision s$e->{id}.$e->{chrev}";
+ $e->{editsum} = $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision $e->{id}.$e->{chrev}";
my $alias_inuse = 'EXISTS(SELECT 1 FROM vn_staff WHERE aid = sa.aid UNION ALL SELECT 1 FROM vn_seiyuu WHERE aid = sa.aid)';
enrich_merge aid => sub { "SELECT aid, $alias_inuse AS inuse, false AS wantdel FROM unnest(", sql_array(@$_), '::int[]) AS sa(aid)' }, $e->{alias};
@@ -51,7 +51,7 @@ TUWF::get qr{/$RE{srev}/edit} => sub {
)->@* if $e->{chrev} != $e->{maxrev};
my $name = (grep $_->{aid} == $e->{aid}, @{$e->{alias}})[0]{name};
- framework_ title => "Edit $name", type => 's', dbobj => $e, tab => 'edit',
+ framework_ title => "Edit $name", dbobj => $e, tab => 'edit',
sub {
editmsg_ s => $e, "Edit $name";
elm_ StaffEdit => $FORM_OUT, $e;
@@ -76,7 +76,7 @@ TUWF::get qr{/s/new}, sub {
elm_api StaffEdit => $FORM_OUT, $FORM_IN, sub {
my $data = shift;
my $new = !$data->{id};
- my $e = $new ? { id => 0 } : db_entry s => $data->{id} or return tuwf->resNotFound;
+ my $e = $new ? { id => 0 } : db_entry $data->{id} or return tuwf->resNotFound;
return elm_Unauth if !can_edit s => $e;
if(!auth->permDbmod) {
@@ -93,7 +93,7 @@ elm_api StaffEdit => $FORM_OUT, $FORM_IN, sub {
# For positive alias IDs: Make sure they exist and are (or were) owned by this entry.
validate_dbid
- sql('SELECT aid FROM staff_alias_hist WHERE chid IN(SELECT id FROM changes WHERE type = \'s\' AND itemid =', \$e->{id}, ') AND aid IN'),
+ sql('SELECT aid FROM staff_alias_hist WHERE chid IN(SELECT id FROM changes WHERE itemid =', \$e->{id}, ') AND aid IN'),
grep $_>=0, map $_->{aid}, $data->{alias}->@*;
# For negative alias IDs: Assign a new ID.
@@ -105,8 +105,8 @@ elm_api StaffEdit => $FORM_OUT, $FORM_IN, sub {
# We rely on Postgres to throw an error if we attempt to delete an alias that is still being referenced.
return elm_Unchanged if !$new && !form_changed $FORM_CMP, $data, $e;
- my($id,undef,$rev) = db_edit s => $e->{id}, $data;
- elm_Redirect "/s$id.$rev";
+ my $ch = db_edit s => $e->{id}, $data;
+ elm_Redirect "/$ch->{nitemid}.$ch->{nrev}";
};
1;
diff --git a/lib/VNWeb/Staff/List.pm b/lib/VNWeb/Staff/List.pm
index 07bcd5d8..d83e7827 100644
--- a/lib/VNWeb/Staff/List.pm
+++ b/lib/VNWeb/Staff/List.pm
@@ -14,7 +14,7 @@ sub listing_ {
ul_ sub {
li_ sub {
abbr_ class => "icons lang $_->{lang}", title => $LANGUAGE{$_->{lang}}, '';
- a_ href => "/s$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
} for @$list;
};
};
diff --git a/lib/VNWeb/Staff/Page.pm b/lib/VNWeb/Staff/Page.pm
index 8f6e0897..c8665eaf 100644
--- a/lib/VNWeb/Staff/Page.pm
+++ b/lib/VNWeb/Staff/Page.pm
@@ -16,7 +16,7 @@ sub enrich_item {
sub _rev_ {
my($s) = @_;
- revision_ s => $s, \&enrich_item,
+ revision_ $s, \&enrich_item,
[ alias => 'Names', fmt => sub {
txt_ $_->{name};
txt_ " ($_->{original})" if $_->{original};
@@ -95,7 +95,7 @@ sub _roles_ {
tr_ sub {
my($v, $a) = ($_, $alias{$_->{aid}});
td_ class => 'tc1', sub {
- a_ href => "/v$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 60;
+ a_ href => "/$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 60;
};
td_ class => 'tc2', sub { rdate_ $v->{c_released} };
td_ class => 'tc3', $CREDIT_TYPE{$v->{role}};
@@ -147,11 +147,11 @@ sub _cast_ {
tr_ sub {
my($v, $a) = ($_, $alias{$_->{aid}});
td_ class => 'tc1', sub {
- a_ href => "/v$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 60;
+ a_ href => "/$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 60;
};
td_ class => 'tc2', sub { rdate_ $v->{c_released} };
td_ class => 'tc3', sub {
- a_ href => "/c$v->{cid}", title => $v->{c_original}||$v->{c_name}, $v->{c_name};
+ a_ href => "/$v->{cid}", title => $v->{c_original}||$v->{c_name}, $v->{c_name};
};
td_ class => 'tc4', title => $a->{original}||$a->{name}, $a->{name};
td_ class => 'tc5', $v->{note};
@@ -162,21 +162,21 @@ sub _cast_ {
TUWF::get qr{/$RE{srev}} => sub {
- my $s = db_entry s => tuwf->capture('id'), tuwf->capture('rev');
+ my $s = db_entry tuwf->captures('id', 'rev');
return tuwf->resNotFound if !$s;
enrich_item $s;
enrich_extlinks s => $s;
my($main) = grep $_->{aid} == $s->{aid}, $s->{alias}->@*;
- framework_ title => $main->{name}, index => !tuwf->capture('rev'), type => 's', dbobj => $s, hiddenmsg => 1,
+ framework_ title => $main->{name}, index => !tuwf->capture('rev'), dbobj => $s, hiddenmsg => 1,
og => {
description => bb_format $s->{desc}, text => 1
},
sub {
_rev_ $s if tuwf->capture('rev');
div_ class => 'mainbox staffpage', sub {
- itemmsg_ s => $s;
+ itemmsg_ $s;
h1_ sub { txt_ $main->{name}; debug_ $s };
h2_ class => 'alttitle', lang => $s->{lang}, $main->{original} if $main->{original};
_infotable_ $main, $s;
diff --git a/lib/VNWeb/TT/TagLinks.pm b/lib/VNWeb/TT/TagLinks.pm
index 656c6b77..4f2f8846 100644
--- a/lib/VNWeb/TT/TagLinks.pm
+++ b/lib/VNWeb/TT/TagLinks.pm
@@ -38,7 +38,7 @@ sub listing_ {
};
td_ class => 'tc6', sub {
a_ href => $url->(v => $i->{vid}, p=>undef), class => 'setfil', '> ' if !defined $opt->{v};
- a_ href => "/v$i->{vid}", shorten $i->{title}, 50;
+ a_ href => "/$i->{vid}", shorten $i->{title}, 50;
};
td_ class => 'tc7', sub { lit_ bb_format $i->{notes}, inline => 1 };
} for @$lst;
@@ -53,8 +53,8 @@ TUWF::get qr{/g/links}, sub {
p => { page => 1 },
o => { onerror => 'd', enum => ['a', 'd'] },
s => { onerror => 'date', enum => [qw|date tag|] },
- v => { onerror => undef, id => 1 },
- u => { onerror => undef, id => 1 },
+ v => { onerror => undef, vndbid => 'v' },
+ u => { onerror => undef, vndbid => 'u' },
t => { onerror => undef, id => 1 },
)->data;
@@ -98,7 +98,7 @@ TUWF::get qr{/g/links}, sub {
li_ sub {
txt_ '['; a_ href => url(v=>undef, p=>undef), 'remove'; txt_ '] ';
txt_ 'Visual novel'; txt_ ' ';
- a_ href => "/v$opt->{v}", tuwf->dbVali('SELECT title FROM vn WHERE id=', \$opt->{v})||'Unknown VN';
+ a_ href => "/$opt->{v}", tuwf->dbVali('SELECT title FROM vn WHERE id=', \$opt->{v})||'Unknown VN';
} if defined $opt->{v};
}
}
diff --git a/lib/VNWeb/ULists/Elm.pm b/lib/VNWeb/ULists/Elm.pm
index 9177496e..e1a61737 100644
--- a/lib/VNWeb/ULists/Elm.pm
+++ b/lib/VNWeb/ULists/Elm.pm
@@ -12,7 +12,7 @@ sub updcache {
our $LABELS = form_compile any => {
- uid => { id => 1 },
+ uid => { vndbid => 'u' },
labels => { aoh => {
id => { int => 1 },
label => { maxlength => 50 },
@@ -77,8 +77,8 @@ elm_api UListManageLabels => undef, $LABELS, sub {
our $VNVOTE = form_compile any => {
- uid => { id => 1 },
- vid => { id => 1 },
+ uid => { vndbid => 'u' },
+ vid => { vndbid => 'v' },
vote => { vnvote => 1 },
};
@@ -101,8 +101,8 @@ elm_api UListVoteEdit => undef, $VNVOTE, sub {
my $VNLABELS = {
- uid => { id => 1 },
- vid => { id => 1 },
+ uid => { vndbid => 'u' },
+ vid => { vndbid => 'v' },
label => { _when => 'in', id => 1 },
applied => { _when => 'in', anybool => 1 },
labels => { _when => 'out', aoh => { id => { int => 1 }, label => {}, private => { anybool => 1 } } },
@@ -136,8 +136,8 @@ elm_api UListLabelEdit => $VNLABELS_OUT, $VNLABELS_IN, sub {
our $VNDATE = form_compile any => {
- uid => { id => 1 },
- vid => { id => 1 },
+ uid => { vndbid => 'u' },
+ vid => { vndbid => 'v' },
date => { required => 0, default => '', regex => qr/^(?:19[7-9][0-9]|20[0-9][0-9])-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$/ }, # 1970 - 2099 for sanity
start => { anybool => 1 }, # Field selection, started/finished
};
@@ -158,8 +158,8 @@ elm_api UListDateEdit => undef, $VNDATE, sub {
our $VNOPT = form_compile any => {
own => { anybool => 1 },
- uid => { id => 1 },
- vid => { id => 1 },
+ uid => { vndbid => 'u' },
+ vid => { vndbid => 'v' },
notes => {},
rels => $VNWeb::Elm::apis{Releases}[0],
relstatus => { type => 'array', values => { uint => 1 } }, # List of release statuses, same order as rels
@@ -167,8 +167,8 @@ our $VNOPT = form_compile any => {
our $VNPAGE = form_compile any => {
- uid => { id => 1 },
- vid => { id => 1 },
+ uid => { vndbid => 'u' },
+ vid => { vndbid => 'v' },
onlist => { anybool => 1 },
canvote => { anybool => 1 },
vote => { vnvote => 1 },
@@ -182,8 +182,8 @@ our $VNPAGE = form_compile any => {
# UListVNNotes module is abused for the UList.Opts and UList.VNPage flag definition
elm_api UListVNNotes => $VNOPT, {
- uid => { id => 1 },
- vid => { id => 1 },
+ uid => { vndbid => 'u' },
+ vid => { vndbid => 'v' },
notes => { required => 0, default => '', maxlength => 2000 },
}, sub {
my($data) = @_;
@@ -199,8 +199,8 @@ elm_api UListVNNotes => $VNOPT, {
elm_api UListDel => undef, {
- uid => { id => 1 },
- vid => { id => 1 },
+ uid => { vndbid => 'u' },
+ vid => { vndbid => 'v' },
}, sub {
my($data) = @_;
return elm_Unauth if !ulists_own $data->{uid};
@@ -215,8 +215,8 @@ elm_api UListDel => undef, {
# Adds the release when not in the list.
# $RLIST_STATUS is also referenced from VNWeb::Releases::Page.
our $RLIST_STATUS = form_compile any => {
- uid => { id => 1 },
- rid => { id => 1 },
+ uid => { vndbid => 'u' },
+ rid => { vndbid => 'r' },
status => { required => 0, uint => 1, enum => \%RLIST_STATUS }, # undef meaning delete
empty => { required => 0, default => '' }, # An 'out' field
};
@@ -248,7 +248,7 @@ our %SAVED_OPTS = (
);
my $SAVED_OPTS = {
- uid => { id => 1 },
+ uid => { vndbid => 'u' },
opts => { type => 'hash', keys => \%SAVED_OPTS },
field => { _when => 'in', enum => [qw/ vnlist votes wish /] },
};
diff --git a/lib/VNWeb/ULists/Export.pm b/lib/VNWeb/ULists/Export.pm
index acfbcccf..655bbd54 100644
--- a/lib/VNWeb/ULists/Export.pm
+++ b/lib/VNWeb/ULists/Export.pm
@@ -72,13 +72,13 @@ TUWF::get qr{/$RE{uid}/list-export/xml}, sub {
tag 'vndb-export' => version => '1.0', date => $d->{'export-date'}, sub {
tag user => sub {
tag name => $d->{user}{name};
- tag url => config->{url}.'/u'.$d->{user}{id};
+ tag url => config->{url}.'/'.$d->{user}{id};
};
tag labels => sub {
tag label => id => $_->{id}, label => $_->{label}, private => $_->{private}?'true':'false', undef for $d->{labels}->@*;
};
tag vns => sub {
- tag vn => id => "v$_->{id}", private => grep(!$_->{private}, $_->{labels}->@*)?'false':'true', sub {
+ tag vn => id => $_->{id}, private => grep(!$_->{private}, $_->{labels}->@*)?'false':'true', sub {
tag title => length($_->{original}) ? (original => $_->{original}) : (), $_->{title};
tag label => id => $_->{id}, label => $_->{label}, undef for $_->{labels}->@*;
tag added => $_->{added};
@@ -87,7 +87,7 @@ TUWF::get qr{/$RE{uid}/list-export/xml}, sub {
tag started => $_->{started} if $_->{started};
tag finished => $_->{finished} if $_->{finished};
tag notes => $_->{notes} if length $_->{notes};
- tag release => id => "r$_->{id}", sub {
+ tag release => id => $_->{id}, sub {
tag title => length($_->{original}) ? (original => $_->{original}) : (), $_->{title};
tag 'release-date' => rdate $_->{released};
tag status => $RLIST_STATUS{$_->{status}};
diff --git a/lib/VNWeb/ULists/Lib.pm b/lib/VNWeb/ULists/Lib.pm
index d831692a..637decfb 100644
--- a/lib/VNWeb/ULists/Lib.pm
+++ b/lib/VNWeb/ULists/Lib.pm
@@ -7,7 +7,7 @@ our @EXPORT = qw/ulists_own/;
# Do we have "ownership" access to this users' list (i.e. can we edit and see private stuff)?
sub ulists_own {
- auth->permUsermod || (auth && auth->uid == shift)
+ auth->permUsermod || (auth && auth->uid eq shift)
}
1;
diff --git a/lib/VNWeb/ULists/List.pm b/lib/VNWeb/ULists/List.pm
index dbdfddc9..ae443955 100644
--- a/lib/VNWeb/ULists/List.pm
+++ b/lib/VNWeb/ULists/List.pm
@@ -132,7 +132,7 @@ sub vn_ {
} if in label => $opt->{c};
td_ class => 'tc_title', sub {
- a_ href => "/v$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 70;
+ a_ href => "/$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 70;
b_ class => 'grayedout', id => 'ulist_notes_'.$v->{id}, $v->{notes} if $v->{notes} || $own;
};
@@ -305,9 +305,9 @@ TUWF::get qr{/$RE{uid}/ulist}, sub {
: $num_core_labels == 1 && $opt_labels->{5} ? 'wish' : 'list';
my $title = $own ? 'My list' : user_displayname($u)."'s list";
- framework_ title => $title, type => 'u', dbobj => $u, tab => $tab, js => 1,
+ framework_ title => $title, dbobj => $u, tab => $tab, js => 1,
$own ? ( pagevars => {
- uid => $u->{id}*1,
+ uid => $u->{id},
labels => $VNWeb::ULists::Elm::LABELS->analyze->{keys}{labels}->coerce_for_json($labels),
voteprivate => (map \($_->{private}?1:0), grep $_->{id} == 7, @$labels),
} ) : (),
@@ -330,7 +330,7 @@ TUWF::get qr{/$RE{uid}/ulist}, sub {
txt_ '(there is currently no import function, more export options may be added later).';
br_;
br_;
- a_ href => "/u$u->{id}/list-export/xml", "Download XML export.";
+ a_ href => "/$u->{id}/list-export/xml", "Download XML export.";
} if $own;
}
};
@@ -341,9 +341,9 @@ TUWF::get qr{/$RE{uid}/ulist}, sub {
# Redirects for old URLs
-TUWF::get qr{/$RE{uid}/votes}, sub { tuwf->resRedirect("/u".tuwf->capture('id').'/ulist?votes=1', 'perm') };
-TUWF::get qr{/$RE{uid}/list}, sub { tuwf->resRedirect("/u".tuwf->capture('id').'/ulist?vnlist=1', 'perm') };
-TUWF::get qr{/$RE{uid}/wish}, sub { tuwf->resRedirect("/u".tuwf->capture('id').'/ulist?wishlist=1', 'perm') };
+TUWF::get qr{/$RE{uid}/votes}, sub { tuwf->resRedirect("/".tuwf->capture('id').'/ulist?votes=1', 'perm') };
+TUWF::get qr{/$RE{uid}/list}, sub { tuwf->resRedirect("/".tuwf->capture('id').'/ulist?vnlist=1', 'perm') };
+TUWF::get qr{/$RE{uid}/wish}, sub { tuwf->resRedirect("/".tuwf->capture('id').'/ulist?wishlist=1', 'perm') };
1;
diff --git a/lib/VNWeb/User/Edit.pm b/lib/VNWeb/User/Edit.pm
index 02161c50..59c0f0d0 100644
--- a/lib/VNWeb/User/Edit.pm
+++ b/lib/VNWeb/User/Edit.pm
@@ -5,7 +5,7 @@ use VNDB::Skins;
my $FORM = {
- id => { uint => 1 },
+ id => { vndbid => 'u' },
title => { _when => 'out' },
username => { username => 1 }, # Can only be modified with perm_usermod
@@ -79,7 +79,7 @@ TUWF::get qr{/$RE{uid}/edit}, sub {
$u->{opts}{perm_boardmod} = auth->permBoardmod;
$u->{opts}{perm_imgmod} = auth->permImgmod;
- $u->{prefs} = $u->{id} == auth->uid || auth->permUsermod ?
+ $u->{prefs} = $u->{id} eq auth->uid || auth->permUsermod ?
tuwf->dbRowi(
'SELECT max_sexual, max_violence, traits_sexual, tags_all, tags_cont, tags_ero, tags_tech, spoilers, skin, customcss
, nodistract_noads, nodistract_nofancy, support_enabled, uniname, pubskin_enabled
@@ -93,7 +93,7 @@ TUWF::get qr{/$RE{uid}/edit}, sub {
$u->{password} = undef;
- $u->{title} = $u->{id} == auth->uid ? 'My Account' : "Edit $u->{username}";
+ $u->{title} = $u->{id} eq auth->uid ? 'My Account' : "Edit $u->{username}";
framework_ title => $u->{title}, type => 'u', dbobj => $u, tab => 'edit',
sub {
elm_ 'User.Edit', $FORM_OUT, $u;
@@ -108,7 +108,7 @@ elm_api UserEdit => $FORM_OUT, $FORM_IN, sub {
return tuwf->resNotFound if !$username;
return elm_Unauth if !can_edit u => $data;
- my $own = $data->{id} == auth->uid || auth->permUsermod;
+ my $own = $data->{id} eq auth->uid || auth->permUsermod;
my %set;
if($own) {
@@ -140,7 +140,7 @@ elm_api UserEdit => $FORM_OUT, $FORM_IN, sub {
return elm_InsecurePass if is_insecurepass $data->{password}{new};
my $ok = 1;
- if(auth->uid == $data->{id}) {
+ if(auth->uid eq $data->{id}) {
$ok = 0 if !auth->setpass($data->{id}, undef, $data->{password}{old}, $data->{password}{new});
} else {
tuwf->dbExeci(select => sql_func user_admin_setpass => \$data->{id}, \auth->uid,
@@ -170,7 +170,7 @@ elm_api UserEdit => $FORM_OUT, $FORM_IN, sub {
."%s"
."\n\n"
."vndb.org",
- $username, $oldmail, $newmail, tuwf->reqBaseURI()."/u$data->{id}/setmail/$token";
+ $username, $oldmail, $newmail, tuwf->reqBaseURI()."/$data->{id}/setmail/$token";
tuwf->mail($body,
To => $newmail,
@@ -188,7 +188,7 @@ elm_api UserEdit => $FORM_OUT, $FORM_IN, sub {
$_ = JSON::XS->new->allow_nonref->encode($_) for values %$old, %$new;
my @diff = grep $old->{$_} ne $new->{$_}, keys %set;
auth->audit($data->{id}, 'user edit', join '; ', map "$_: $old->{$_} -> $new->{$_}", @diff)
- if @diff && (auth->uid != $data->{id} || grep /^(perm_|ign_votes|username)/, @diff);
+ if @diff && (auth->uid ne $data->{id} || grep /^(perm_|ign_votes|username)/, @diff);
$ret->();
};
diff --git a/lib/VNWeb/User/List.pm b/lib/VNWeb/User/List.pm
index 4a540085..dae3a6a8 100644
--- a/lib/VNWeb/User/List.pm
+++ b/lib/VNWeb/User/List.pm
@@ -27,19 +27,19 @@ sub listing_ {
td_ class => 'tc2', fmtdate $l->{registered};
td_ class => 'tc3', sub {
txt_ '0' if !$l->{c_vns};
- a_ href => "/u$l->{user_id}/ulist?vnlist=1", $l->{c_vns} if $l->{c_vns};
+ a_ href => "/$l->{user_id}/ulist?vnlist=1", $l->{c_vns} if $l->{c_vns};
};
td_ class => 'tc4', sub {
txt_ '0' if !$l->{c_votes};
- a_ href => "/u$l->{user_id}/ulist?votes=1", $l->{c_votes} if $l->{c_votes};
+ a_ href => "/$l->{user_id}/ulist?votes=1", $l->{c_votes} if $l->{c_votes};
};
td_ class => 'tc5', sub {
txt_ '0' if !$l->{c_wish};
- a_ href => "/u$l->{user_id}/ulist?wishlist=1", $l->{c_wish} if $l->{c_wish};
+ a_ href => "/$l->{user_id}/ulist?wishlist=1", $l->{c_wish} if $l->{c_wish};
};
td_ class => 'tc6', sub {
txt_ '-' if !$l->{c_changes};
- a_ href => "/u$l->{user_id}/hist", $l->{c_changes} if $l->{c_changes};
+ a_ href => "/$l->{user_id}/hist", $l->{c_changes} if $l->{c_changes};
};
td_ class => 'tc7', sub {
txt_ '-' if !$l->{c_tags};
@@ -70,7 +70,7 @@ TUWF::get qr{/u/(?<char>[0a-z]|all)}, sub {
$char eq 'all' ? () : $char eq '0' ? "ascii(username) not between ascii('a') and ascii('z')" : "username like '$char%'",
$opt->{q} ? sql_or(
auth->permUsermod && $opt->{q} =~ /@/ ? sql('id IN(SELECT y FROM user_emailtoid(', \$opt->{q}, ') x(y))') : (),
- $opt->{q} =~ /^u?([0-9]{1,6})$/ ? sql 'id =', \"$1" : (),
+ $opt->{q} =~ /^(u?[0-9]{1,6})$/ ? sql 'id =', \"$1" : (),
sql('username ILIKE', \('%'.sql_like($opt->{q}).'%')),
) : ()
);
@@ -78,7 +78,7 @@ TUWF::get qr{/u/(?<char>[0a-z]|all)}, sub {
my $list = tuwf->dbPagei({ results => 50, page => $opt->{p} },
'SELECT', sql_user(), ',', sql_totime('registered'), 'as registered, c_vns, c_votes, c_wish, c_changes, c_tags, c_imgvotes
FROM users u
- WHERE', sql_and('id > 0', @where),
+ WHERE', sql_and(@where),
'ORDER BY', {
username => 'username',
registered => 'id',
diff --git a/lib/VNWeb/User/Login.pm b/lib/VNWeb/User/Login.pm
index a552c60f..fa679325 100644
--- a/lib/VNWeb/User/Login.pm
+++ b/lib/VNWeb/User/Login.pm
@@ -60,7 +60,7 @@ elm_api UserChangePass => undef, {
TUWF::post qr{/$RE{uid}/logout}, sub {
- return tuwf->resNotFound if !auth || auth->uid != tuwf->capture('id') || (tuwf->reqPost('csrf')||'') ne auth->csrftoken;
+ return tuwf->resNotFound if !auth || auth->uid ne tuwf->capture('id') || (tuwf->reqPost('csrf')||'') ne auth->csrftoken;
auth->logout;
tuwf->resRedirect('/', 'post');
};
diff --git a/lib/VNWeb/User/Notifications.pm b/lib/VNWeb/User/Notifications.pm
index 1f1d964f..2e6bc7d4 100644
--- a/lib/VNWeb/User/Notifications.pm
+++ b/lib/VNWeb/User/Notifications.pm
@@ -23,7 +23,7 @@ sub settings_ {
my $u = tuwf->dbRowi('SELECT notify_dbedit, notify_post, notify_comment, notify_announce FROM users WHERE id =', \$id);
h1_ 'Settings';
- form_ action => "/u$id/notify_options", method => 'POST', sub {
+ form_ action => "/$id/notify_options", method => 'POST', sub {
input_ type => 'hidden', class => 'hidden', name => 'csrf', value => auth->csrftoken;
p_ sub {
label_ sub {
@@ -55,7 +55,7 @@ sub settings_ {
sub listing_ {
my($id, $opt, $count, $list) = @_;
- my sub url { "/u$id/notifies?r=$opt->{r}&p=$_" }
+ my sub url { "/$id/notifies?r=$opt->{r}&p=$_" }
my sub tbl_ {
thead_ sub { tr_ sub {
@@ -101,7 +101,7 @@ sub listing_ {
} for @$list;
}
- form_ action => "/u$id/notify_update", method => 'POST', sub {
+ form_ action => "/$id/notify_update", method => 'POST', sub {
input_ type => 'hidden', class => 'hidden', name => 'url', value => do { local $_ = $opt->{p}; url };
paginate_ \&url, $opt->{p}, [$count, 25], 't';
div_ class => 'mainbox browse notifies', sub {
@@ -113,12 +113,12 @@ sub listing_ {
# Redirect so that elm/Subscribe.elm can link to this page without knowing our uid.
-TUWF::get qr{/u/notifies}, sub { auth ? tuwf->resRedirect('/u'.auth->uid.'/notifies') : tuwf->resNotFound };
+TUWF::get qr{/u/notifies}, sub { auth ? tuwf->resRedirect('/'.auth->uid.'/notifies') : tuwf->resNotFound };
TUWF::get qr{/$RE{uid}/notifies}, sub {
my $id = tuwf->capture('id');
- return tuwf->resNotFound if !auth || $id != auth->uid;
+ return tuwf->resNotFound if !auth || $id ne auth->uid;
my $opt = tuwf->validate(get =>
p => { page => 1 },
@@ -158,7 +158,7 @@ TUWF::get qr{/$RE{uid}/notifies}, sub {
TUWF::post qr{/$RE{uid}/notify_options}, sub {
my $id = tuwf->capture('id');
- return tuwf->resNotFound if !auth || $id != auth->uid;
+ return tuwf->resNotFound if !auth || $id ne auth->uid;
my $frm = tuwf->validate(post =>
csrf => {},
@@ -175,16 +175,16 @@ TUWF::post qr{/$RE{uid}/notify_options}, sub {
notify_post => $frm->{post},
notify_comment => $frm->{comment},
}, 'WHERE id =', \$id);
- tuwf->resRedirect("/u$id/notifies", 'post');
+ tuwf->resRedirect("/$id/notifies", 'post');
};
TUWF::post qr{/$RE{uid}/notify_update}, sub {
my $id = tuwf->capture('id');
- return tuwf->resNotFound if !auth || $id != auth->uid;
+ return tuwf->resNotFound if !auth || $id ne auth->uid;
my $frm = tuwf->validate(post =>
- url => { regex => qr{^/u$id/notifies} },
+ url => { regex => qr{^/$id/notifies} },
notifysel => { required => 0, default => [], type => 'array', scalar => 1, values => { id => 1 } },
markread => { anybool => 1 },
remove => { anybool => 1 },
@@ -203,7 +203,7 @@ TUWF::post qr{/$RE{uid}/notify_update}, sub {
# (but that's subject to change in the future, so let's keep this around)
TUWF::get qr{/$RE{uid}/notify/$RE{num}/(?<lid>[a-z0-9\.]+)}, sub {
my $id = tuwf->capture('id');
- return tuwf->resNotFound if !auth || $id != auth->uid;
+ return tuwf->resNotFound if !auth || $id ne auth->uid;
tuwf->dbExeci('UPDATE notifications SET read = NOW() WHERE read IS NULL AND uid =', \$id, ' AND id =', \tuwf->capture('num'));
tuwf->resRedirect('/'.tuwf->capture('lid'), 'temp');
};
diff --git a/lib/VNWeb/User/Page.pm b/lib/VNWeb/User/Page.pm
index f225bd76..b110a444 100644
--- a/lib/VNWeb/User/Page.pm
+++ b/lib/VNWeb/User/Page.pm
@@ -22,7 +22,7 @@ sub _info_table_ {
td_ class => 'key', 'Username';
td_ sub {
txt_ ucfirst $u->{user_name};
- txt_ ' ('; a_ href => "/u$u->{id}", "u$u->{id}";
+ txt_ ' ('; a_ href => "/$u->{id}", $u->{id};
txt_ ')';
debug_ $u;
sup if !($u->{user_uniname_can} && $u->{user_uniname});
@@ -35,7 +35,7 @@ sub _info_table_ {
tr_ sub {
td_ 'Edits';
td_ !$u->{c_changes} ? '-' : sub {
- a_ href => "/u$u->{id}/hist", $u->{c_changes}
+ a_ href => "/$u->{id}/hist", $u->{c_changes}
};
};
tr_ sub {
@@ -44,7 +44,7 @@ sub _info_table_ {
td_ 'Votes';
td_ !$num ? '-' : sub {
txt_ sprintf '%d vote%s, %.2f average. ', $num, $num == 1 ? '' : 's', $sum/$num/10;
- a_ href => "/u$u->{id}/ulist?votes=1", 'Browse votes »';
+ a_ href => "/$u->{id}/ulist?votes=1", 'Browse votes »';
}
};
tr_ sub {
@@ -62,7 +62,7 @@ sub _info_table_ {
txt_ sprintf '%d release%s of %d visual novel%s. ',
$rel, $rel == 1 ? '' : 's',
$vns, $vns == 1 ? '' : 's';
- a_ href => "/u$u->{id}/ulist?vnlist=1", 'Browse list »';
+ a_ href => "/$u->{id}/ulist?vnlist=1", 'Browse list »';
};
};
tr_ sub {
@@ -99,7 +99,7 @@ sub _info_table_ {
txt_ sprintf '%d post%s, %d new thread%s. ',
$stats->{posts}, $stats->{posts} == 1 ? '' : 's',
$stats->{threads}, $stats->{threads} == 1 ? '' : 's';
- a_ href => "/u$u->{id}/posts", 'Browse posts »';
+ a_ href => "/$u->{id}/posts", 'Browse posts »';
};
};
}
@@ -140,11 +140,11 @@ sub _votestats_ {
table_ class => 'recentvotes stripe', sub {
thead_ sub { tr_ sub { td_ colspan => 3, sub {
txt_ 'Recent votes';
- b_ sub { txt_ ' ('; a_ href => "/u$u->{id}/ulist?votes=1", 'show all'; txt_ ')' };
+ b_ sub { txt_ ' ('; a_ href => "/$u->{id}/ulist?votes=1", 'show all'; txt_ ')' };
} } };
tr_ sub {
my $v = $_;
- td_ sub { a_ href => "/v$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 30 };
+ td_ sub { a_ href => "/$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 30 };
td_ fmtvote $v->{vote};
td_ fmtdate $v->{date};
} for @$recent;
@@ -164,7 +164,7 @@ TUWF::get qr{/$RE{uid}}, sub {
);
return tuwf->resNotFound if !$u->{id};
- my $own = (auth && auth->uid == $u->{id}) || auth->permUsermod;
+ my $own = (auth && auth->uid eq $u->{id}) || auth->permUsermod;
$u->{votes} = tuwf->dbAlli('
SELECT (uv.vote::numeric/10)::int AS idx, COUNT(uv.vote) as votes, SUM(uv.vote) AS total
@@ -177,7 +177,7 @@ TUWF::get qr{/$RE{uid}}, sub {
');
my $title = user_displayname($u)."'s profile";
- framework_ title => $title, type => 'u', dbobj => $u,
+ framework_ title => $title, dbobj => $u,
sub {
div_ class => 'mainbox userpage', sub {
h1_ $title;
@@ -190,8 +190,8 @@ TUWF::get qr{/$RE{uid}}, sub {
} if grep $_->{votes} > 0, $u->{votes}->@*;
if($u->{c_changes}) {
- h1_ class => 'boxtitle', sub { a_ href => "/u$u->{id}/hist", 'Recent changes' };
- VNWeb::Misc::History::tablebox_ u => $u->{id}, {p=>1}, nopage => 1, results => 10;
+ h1_ class => 'boxtitle', sub { a_ href => "/$u->{id}/hist", 'Recent changes' };
+ VNWeb::Misc::History::tablebox_ $u->{id}, {p=>1}, nopage => 1, results => 10;
}
};
};
diff --git a/lib/VNWeb/User/PassReset.pm b/lib/VNWeb/User/PassReset.pm
index 39f1d6ea..8d40295a 100644
--- a/lib/VNWeb/User/PassReset.pm
+++ b/lib/VNWeb/User/PassReset.pm
@@ -29,7 +29,7 @@ elm_api UserPassReset => undef, {
."Now don't forget your password again! :-)"
."\n\n"
."vndb.org",
- $name, tuwf->reqBaseURI()."/u$id/setpass/$token";
+ $name, tuwf->reqBaseURI()."/$id/setpass/$token";
tuwf->mail($body,
To => $data->{email},
diff --git a/lib/VNWeb/User/PassSet.pm b/lib/VNWeb/User/PassSet.pm
index 4b5d3fc1..2428f8e1 100644
--- a/lib/VNWeb/User/PassSet.pm
+++ b/lib/VNWeb/User/PassSet.pm
@@ -3,7 +3,7 @@ package VNWeb::User::PassSet;
use VNWeb::Prelude;
my $FORM = {
- uid => { id => 1 },
+ uid => { vndbid => 'u' },
token => { regex => qr/[a-f0-9]{40}/ },
password => { _when => 'in', password => 1 },
};
diff --git a/lib/VNWeb/User/Register.pm b/lib/VNWeb/User/Register.pm
index c956111c..89e34846 100644
--- a/lib/VNWeb/User/Register.pm
+++ b/lib/VNWeb/User/Register.pm
@@ -46,7 +46,7 @@ elm_api UserRegister => undef, {
."If you don't remember creating an account on VNDB.org recently, please ignore this e-mail."
."\n\n"
."vndb.org",
- $data->{username}, tuwf->reqBaseURI()."/u$id/setpass/$token";
+ $data->{username}, tuwf->reqBaseURI()."/$id/setpass/$token";
tuwf->mail($body,
To => $data->{email},
diff --git a/lib/VNWeb/VN/Edit.pm b/lib/VNWeb/VN/Edit.pm
index ec0445ed..5e50861f 100644
--- a/lib/VNWeb/VN/Edit.pm
+++ b/lib/VNWeb/VN/Edit.pm
@@ -6,7 +6,7 @@ use VNWeb::Releases::Lib;
my $FORM = {
- id => { required => 0, id => 1 },
+ id => { required => 0, vndbid => 'v' },
title => { maxlength => 250 },
original => { required => 0, default => '', maxlength => 250 },
alias => { required => 0, default => '', maxlength => 500 },
@@ -16,7 +16,7 @@ my $FORM = {
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 },
+ vid => { vndbid => 'v' },
relation => { enum => \%VN_RELATION },
official => { anybool => 1 },
title => { _when => 'out' },
@@ -33,22 +33,22 @@ my $FORM = {
aid => { id => 1 },
role => { enum => \%CREDIT_TYPE },
note => { required => 0, default => '', maxlength => 250 },
- id => { _when => 'out', id => 1 },
+ id => { _when => 'out', vndbid => 's' },
name => { _when => 'out' },
original => { _when => 'out', required => 0, default => '' },
} },
seiyuu => { sort_keys => ['aid','cid'], aoh => {
aid => { id => 1 },
- cid => { id => 1 },
+ cid => { vndbid => 'c' },
note => { required => 0, default => '', maxlength => 250 },
# Staff info
- id => { _when => 'out', id => 1 },
+ id => { _when => 'out', vndbid => 's' },
name => { _when => 'out' },
original => { _when => 'out', required => 0, default => '' },
} },
screenshots=> { sort_keys => 'scr', aoh => {
scr => { vndbid => 'sf' },
- rid => { required => 0, id => 1 },
+ rid => { required => 0, vndbid => 'r' },
info => { _when => 'out', type => 'hash', keys => $VNWeb::Elm::apis{ImageResult}[0]{aoh} },
} },
hidden => { anybool => 1 },
@@ -58,7 +58,7 @@ my $FORM = {
editsum => { _when => 'in out', editsum => 1 },
releases => { _when => 'out', $VNWeb::Elm::apis{Releases}[0]->%* },
chars => { _when => 'out', aoh => {
- id => { id => 1 },
+ id => { vndbid => 'c' },
name => {},
original => { required => 0, default => '' },
} },
@@ -70,11 +70,11 @@ my $FORM_CMP = form_compile cmp => $FORM;
TUWF::get qr{/$RE{vrev}/edit} => sub {
- my $e = db_entry v => tuwf->capture('id'), tuwf->capture('rev') or return tuwf->resNotFound;
+ my $e = db_entry tuwf->captures('id', 'rev') or return tuwf->resNotFound;
return tuwf->resDenied if !can_edit v => $e;
$e->{authmod} = auth->permDbmod;
- $e->{editsum} = $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision v$e->{id}.$e->{chrev}";
+ $e->{editsum} = $e->{chrev} == $e->{maxrev} ? '' : "Reverted to revision $e->{id}.$e->{chrev}";
if($e->{image}) {
$e->{image_info} = { id => $e->{image} };
@@ -103,7 +103,7 @@ TUWF::get qr{/$RE{vrev}/edit} => sub {
ORDER BY name, id'
);
- framework_ title => "Edit $e->{title}", type => 'v', dbobj => $e, tab => 'edit',
+ framework_ title => "Edit $e->{title}", dbobj => $e, tab => 'edit',
sub {
editmsg_ v => $e, "Edit $e->{title}";
elm_ VNEdit => $FORM_OUT, $e;
@@ -125,7 +125,7 @@ TUWF::get qr{/v/add}, sub {
elm_api VNEdit => $FORM_OUT, $FORM_IN, sub {
my $data = shift;
my $new = !$data->{id};
- my $e = $new ? { id => 0 } : db_entry v => $data->{id} or return tuwf->resNotFound;
+ my $e = $new ? { id => 0 } : db_entry $data->{id} or return tuwf->resNotFound;
return elm_Unauth if !can_edit v => $e;
if(!auth->permDbmod) {
@@ -143,7 +143,7 @@ elm_api VNEdit => $FORM_OUT, $FORM_IN, sub {
$data->{relations} = [] if $data->{hidden};
validate_dbid 'SELECT id FROM vn WHERE id IN', map $_->{vid}, $data->{relations}->@*;
- die "Relation with self" if grep $_->{vid} == $e->{id}, $data->{relations}->@*;
+ die "Relation with self" if grep $_->{vid} eq $e->{id}, $data->{relations}->@*;
die "Screenshot without releases assigned" if grep !$_->{rid}, $data->{screenshots}->@*; # This is only the case for *very* old revisions, form disallows this now.
# Allow linking to deleted or moved releases only if the previous revision also had that.
@@ -166,9 +166,9 @@ elm_api VNEdit => $FORM_OUT, $FORM_IN, sub {
$_->{nsfw} = $oldscr{$_->{scr}}||0 for $data->{screenshots}->@*;
return elm_Unchanged if !$new && !form_changed $FORM_CMP, $data, $e;
- my($id,undef,$rev) = db_edit v => $e->{id}, $data;
- update_reverse($id, $rev, $e, $data);
- elm_Redirect "/v$id.$rev";
+ my $ch = db_edit v => $e->{id}, $data;
+ update_reverse($ch->{nitemid}, $ch->{nrev}, $e, $data);
+ elm_Redirect "/$ch->{nitemid}.$ch->{nrev}";
};
@@ -194,13 +194,13 @@ sub update_reverse {
}
for my $i (keys %upd) {
- my $v = db_entry v => $i;
+ my $v = db_entry $i;
$v->{relations} = [
$upd{$i} ? $upd{$i} : (),
- grep $_->{vid} != $id, $v->{relations}->@*
+ grep $_->{vid} ne $id, $v->{relations}->@*
];
- $v->{editsum} = "Reverse relation update caused by revision v$id.$rev";
- db_edit v => $i, $v, 1;
+ $v->{editsum} = "Reverse relation update caused by revision $id.$rev";
+ db_edit v => $i, $v, 'u1';
}
}
diff --git a/lib/VNWeb/VN/Graph.pm b/lib/VNWeb/VN/Graph.pm
index e00f656e..a9227108 100644
--- a/lib/VNWeb/VN/Graph.pm
+++ b/lib/VNWeb/VN/Graph.pm
@@ -34,26 +34,26 @@ TUWF::get qr{/$RE{vid}/rg}, sub {
my @lines;
my $params = "?num=$num&unoff=$unoff";
- for my $n (sort { $a->{id} <=> $b->{id} } values %$nodes) {
+ for my $n (sort { idcmp $a->{id}, $b->{id} } values %$nodes) {
my $title = val_escape shorten $n->{title}, 27;
my $tooltip = val_escape $n->{title};
my $date = rdate $n->{c_released};
my $lang = $n->{lang}||'N/A';
my $nodeid = $n->{distance} == 0 ? 'id = "graph_current", ' : '';
push @lines,
- qq|n$n->{id} [ $nodeid URL = "/v$n->{id}", tooltip = "$tooltip", label=<|.
+ qq|n$n->{id} [ $nodeid URL = "/$n->{id}", tooltip = "$tooltip", label=<|.
qq|<TABLE CELLSPACING="0" CELLPADDING="2" BORDER="0" CELLBORDER="1" BGCOLOR="#222222">|.
qq|<TR><TD COLSPAN="2" ALIGN="CENTER" CELLPADDING="3"><FONT POINT-SIZE="9"> $title </FONT></TD></TR>|.
qq|<TR><TD> $date </TD><TD> $lang </TD></TR>|.
qq|</TABLE>> ]|;
- push @lines, node_more $n->{id}, "/v$n->{id}/rg$params", scalar grep !$nodes->{$_}, $n->{rels}->@*;
+ push @lines, node_more $n->{id}, "/$n->{id}/rg$params", scalar grep !$nodes->{$_}, $n->{rels}->@*;
}
$rel = [ grep $nodes->{$_->{id0}} && $nodes->{$_->{id1}}, @$rel ];
my $dot = gen_dot \@lines, $nodes, $rel, \%VN_RELATION;
- framework_ title => "Relations for $v->{title}", type => 'v', dbobj => $v, tab => 'rg',
+ framework_ title => "Relations for $v->{title}", dbobj => $v, tab => 'rg',
sub {
div_ class => 'mainbox', style => 'float: left; min-width: 100%', sub {
h1_ "Relations for $v->{title}";
@@ -78,7 +78,7 @@ TUWF::get qr{/$RE{vid}/rg}, sub {
if($_ == min $num, $total_nodes) {
txt_ $_ ;
} else {
- a_ href => "/v$id/rg?num=$_", $_;
+ a_ href => "/$id/rg?num=$_", $_;
}
}, grep($_ < $total_nodes, 10, 15, 25, 50, 75, 100, 150, 250, 500, 750, 1000), $total_nodes;
}
diff --git a/lib/VNWeb/VN/List.pm b/lib/VNWeb/VN/List.pm
index 4949e139..928ac0bb 100644
--- a/lib/VNWeb/VN/List.pm
+++ b/lib/VNWeb/VN/List.pm
@@ -27,7 +27,7 @@ sub listing_ {
} };
tr_ sub {
td_ class => 'tc_s',sub { tagscore_ $_->{tagscore} } if $tagscore;
- td_ class => $tagscore ? 'tc_t' : 'tc1', sub { a_ href => "/v$_->{id}", title => $_->{original}||$_->{title}, $_->{title} };
+ td_ class => $tagscore ? 'tc_t' : 'tc1', sub { a_ href => "/$_->{id}", title => $_->{original}||$_->{title}, $_->{title} };
td_ class => 'tc7', sub {
b_ class => $_->{userlist_obtained} == $_->{userlist_all} ? 'done' : 'todo', sprintf '%d/%d', $_->{userlist_obtained}, $_->{userlist_all} if $_->{userlist_all};
abbr_ title => join(', ', $_->{vnlist_labels}->@*), scalar $_->{vnlist_labels}->@* if $_->{vnlist_labels} && $_->{vnlist_labels}->@*;
@@ -134,7 +134,7 @@ TUWF::get qr{/v(?:/(?<char>all|[a-z0]))?}, sub {
) : [];
} || (($count, $list) = (undef, []));
- return tuwf->resRedirect("/v$list->[0]{id}") if $count && $count == 1 && $opt->{q} && !defined $opt->{ch};
+ return tuwf->resRedirect("/$list->[0]{id}") if $count && $count == 1 && $opt->{q} && !defined $opt->{ch};
enrich_userlist $list;
$time = time - $time;
diff --git a/lib/VNWeb/VN/Page.pm b/lib/VNWeb/VN/Page.pm
index ff1708df..ba413fb3 100644
--- a/lib/VNWeb/VN/Page.pm
+++ b/lib/VNWeb/VN/Page.pm
@@ -55,10 +55,10 @@ sub enrich_item {
enrich_merge aid => 'SELECT id AS sid, aid, name, original FROM staff_alias WHERE aid IN', $v->{staff}, $v->{seiyuu};
enrich_merge cid => 'SELECT id AS cid, name AS char_name, original AS char_original FROM chars WHERE id IN', $v->{seiyuu};
- $v->{relations} = [ sort { $a->{vid} <=> $b->{vid} } $v->{relations}->@* ];
+ $v->{relations} = [ sort { idcmp($a->{vid}, $b->{vid}) } $v->{relations}->@* ];
$v->{anime} = [ sort { $a->{aid} <=> $b->{aid} } $v->{anime}->@* ];
$v->{staff} = [ sort { $a->{aid} <=> $b->{aid} || $a->{role} cmp $b->{role} } $v->{staff}->@* ];
- $v->{seiyuu} = [ sort { $a->{aid} <=> $b->{aid} || $a->{cid} <=> $b->{cid} || $a->{note} cmp $b->{note} } $v->{seiyuu}->@* ];
+ $v->{seiyuu} = [ sort { $a->{aid} <=> $b->{aid} || idcmp($a->{cid}, $b->{cid}) || $a->{note} cmp $b->{note} } $v->{seiyuu}->@* ];
$v->{screenshots} = [ sort { idcmp($a->{scr}{id}, $b->{scr}{id}) } $v->{screenshots}->@* ];
}
@@ -83,7 +83,7 @@ sub canvote {
sub rev_ {
my($v) = @_;
- revision_ v => $v, \&enrich_item,
+ revision_ $v, \&enrich_item,
[ title => 'Title (romaji)' ],
[ original => 'Original title' ],
[ alias => 'Alias' ],
@@ -91,26 +91,26 @@ sub rev_ {
[ desc => 'Description' ],
[ length => 'Length', fmt => \%VN_LENGTH ],
[ staff => 'Credits', fmt => sub {
- a_ href => "/s$_->{sid}", title => $_->{original}||$_->{name}, $_->{name} if $_->{sid};
+ a_ href => "/$_->{sid}", title => $_->{original}||$_->{name}, $_->{name} if $_->{sid};
b_ class => 'grayedout', '[removed alias]' if !$_->{sid};
txt_ " [$CREDIT_TYPE{$_->{role}}]";
txt_ " [$_->{note}]" if $_->{note};
}],
[ seiyuu => 'Seiyuu', fmt => sub {
- a_ href => "/s$_->{sid}", title => $_->{original}||$_->{name}, $_->{name} if $_->{sid};
+ a_ href => "/$_->{sid}", title => $_->{original}||$_->{name}, $_->{name} if $_->{sid};
b_ class => 'grayedout', '[removed alias]' if !$_->{sid};
txt_ ' as ';
- a_ href => "/c$_->{cid}", title => $_->{char_original}||$_->{char_name}, $_->{char_name};
+ a_ href => "/$_->{cid}", title => $_->{char_original}||$_->{char_name}, $_->{char_name};
txt_ " [$_->{note}]" if $_->{note};
}],
[ relations => 'Relations', fmt => sub {
txt_ sprintf '[%s] %s: ', $_->{official} ? 'official' : 'unofficial', $VN_RELATION{$_->{relation}}{txt};
- a_ href => "/v$_->{vid}", title => $_->{original}||$_->{title}, $_->{title};
+ a_ href => "/$_->{vid}", title => $_->{original}||$_->{title}, $_->{title};
}],
[ anime => 'Anime', fmt => sub { a_ href => "https://anidb.net/anime/$_->{aid}", "a$_->{aid}" }],
[ screenshots => 'Screenshots', fmt => sub {
txt_ '[';
- a_ href => "/r$_->{rid}", "r$_->{rid}" if $_->{rid};
+ a_ href => "/$_->{rid}", $_->{rid} if $_->{rid};
txt_ 'no release' if !$_->{rid};
txt_ '] ';
a_ href => imgurl($_->{scr}{id}), 'data-iv' => "$_->{scr}{width}x$_->{scr}{height}::$_->{scr}{sexual}$_->{scr}{violence}$_->{scr}{votecount}", $_->{scr}{id};
@@ -141,7 +141,7 @@ sub infobox_relations_ {
dd_ sub {
join_ \&br_, sub {
b_ class => 'grayedout', '[unofficial] ' if !$_->{official};
- a_ href => "/v$_->{vid}", title => $_->{original}||$_->{title}, shorten $_->{title}, 40;
+ a_ href => "/$_->{vid}", title => $_->{original}||$_->{title}, shorten $_->{title}, 40;
}, $rel{$_}->@*;
}
}
@@ -173,7 +173,7 @@ sub infobox_producers_ {
tr_ sub {
td_ 'Developer';
td_ sub {
- join_ ' & ', sub { a_ href => "/p$_->{id}", title => $_->{original}||$_->{name}, $_->{name}; }, @dev;
+ join_ ' & ', sub { a_ href => "/$_->{id}", title => $_->{original}||$_->{name}, $_->{name}; }, @dev;
};
} if @dev;
@@ -188,7 +188,7 @@ sub infobox_producers_ {
td_ sub {
join_ \&br_, sub {
abbr_ class => "icons lang $_", title => $LANGUAGE{$_}, '';
- join_ ' & ', sub { a_ href => "/p$_->{id}", $_->{official} ? () : (class => 'grayedout'), title => $_->{original}||$_->{name}, $_->{name} }, $lang{$_}->@*;
+ join_ ' & ', sub { a_ href => "/$_->{id}", $_->{official} ? () : (class => 'grayedout'), title => $_->{original}||$_->{name}, $_->{name} }, $lang{$_}->@*;
}, @lang;
}
} if keys %lang;
@@ -338,7 +338,7 @@ sub infobox_useroptions_ {
sub infobox_ {
my($v, $notags) = @_;
div_ class => 'mainbox', sub {
- itemmsg_ v => $v;
+ itemmsg_ $v;
h1_ $v->{title};
h2_ class => 'alttitle', lang_attr($v->{olang}), $v->{original} if $v->{original};
@@ -405,25 +405,25 @@ sub tabs_ {
$tab ||= '';
div_ class => 'maintabs', sub {
ul_ sub {
- li_ class => ($tab eq '' ? ' tabselected' : ''), sub { a_ href => "/v$v->{id}#main", name => 'main', 'main' };
- li_ class => ($tab eq 'tags' ? ' tabselected' : ''), sub { a_ href => "/v$v->{id}/tags#tags", name => 'tags', 'tags' };
- li_ class => ($tab eq 'chars' ? ' tabselected' : ''), sub { a_ href => "/v$v->{id}/chars#chars", name => 'chars', "characters ($chars)" } if $chars;
+ li_ class => ($tab eq '' ? ' tabselected' : ''), sub { a_ href => "/$v->{id}#main", name => 'main', 'main' };
+ li_ class => ($tab eq 'tags' ? ' tabselected' : ''), sub { a_ href => "/$v->{id}/tags#tags", name => 'tags', 'tags' };
+ li_ class => ($tab eq 'chars' ? ' tabselected' : ''), sub { a_ href => "/$v->{id}/chars#chars", name => 'chars', "characters ($chars)" } if $chars;
if($v->{reviews}{mini} > 4 || $tab eq 'minireviews' || $tab eq 'fullreviews') {
- li_ class => ($tab eq 'minireviews'?' tabselected' : ''), sub { a_ href => "/v$v->{id}/minireviews#review", name => 'review', "mini reviews ($v->{reviews}{mini})" } if $v->{reviews}{mini};
- li_ class => ($tab eq 'fullreviews'?' tabselected' : ''), sub { a_ href => "/v$v->{id}/fullreviews#review", name => 'review', "full reviews ($v->{reviews}{full})" } if $v->{reviews}{full};
+ li_ class => ($tab eq 'minireviews'?' tabselected' : ''), sub { a_ href => "/$v->{id}/minireviews#review", name => 'review', "mini reviews ($v->{reviews}{mini})" } if $v->{reviews}{mini};
+ li_ class => ($tab eq 'fullreviews'?' tabselected' : ''), sub { a_ href => "/$v->{id}/fullreviews#review", name => 'review', "full reviews ($v->{reviews}{full})" } if $v->{reviews}{full};
} elsif($v->{reviews}{mini} || $v->{reviews}{full}) {
- li_ class => ($tab =~ /reviews/ ?' tabselected':''), sub { a_ href => "/v$v->{id}/reviews#review", name => 'review', sprintf 'reviews (%d)', $v->{reviews}{total} };
+ li_ class => ($tab =~ /reviews/ ?' tabselected':''), sub { a_ href => "/$v->{id}/reviews#review", name => 'review', sprintf 'reviews (%d)', $v->{reviews}{total} };
}
};
ul_ sub {
if(auth && canvote $v) {
my $id = tuwf->dbVali('SELECT id FROM reviews WHERE vid =', \$v->{id}, 'AND uid =', \auth->uid);
- li_ sub { a_ href => "/v$v->{id}/addreview", 'add review' } if !$id && can_edit w => {};
+ li_ sub { a_ href => "/$v->{id}/addreview", 'add review' } if !$id && can_edit w => {};
li_ sub { a_ href => "/$id/edit", 'edit review' } if $id;
}
if(auth->permEdit) {
- li_ sub { a_ href => "/v$v->{id}/add", 'add release' };
- li_ sub { a_ href => "/v$v->{id}/addchar", 'add character' };
+ li_ sub { a_ href => "/$v->{id}/add", 'add release' };
+ li_ sub { a_ href => "/$v->{id}/addchar", 'add character' };
}
};
}
@@ -436,7 +436,7 @@ sub releases_ {
# TODO: Organize a long list of releases a bit better somehow? Collapsable language sections?
enrich_release $v->{releases};
- $v->{releases} = [ sort { $a->{released} <=> $b->{released} || $a->{id} <=> $b->{id} } $v->{releases}->@* ];
+ $v->{releases} = [ sort { $a->{released} <=> $b->{released} || idcmp($a->{id}, $b->{id}) } $v->{releases}->@* ];
my %lang;
my @lang = grep !$lang{$_}++, map $_->{lang}->@*, $v->{releases}->@*;
@@ -484,7 +484,7 @@ sub staff_ {
xml_string sub {
li_ class => 'vnstaff_head', $CREDIT_TYPE{$_};
li_ sub {
- a_ href => "/s$_->{sid}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{sid}", title => $_->{original}||$_->{name}, $_->{name};
b_ title => $_->{note}, class => 'grayedout', $_->{note} if $_->{note};
} for sort { $a->{name} cmp $b->{name} } $roles{$_}->@*;
}
@@ -540,7 +540,7 @@ sub charsum_ {
div_ class => 'mainbox', 'data-mainbox-summarize' => 200, sub {
p_ class => 'mainopts', sub {
- a_ href => "/v$v->{id}/chars#chars", 'Full character list';
+ a_ href => "/$v->{id}/chars#chars", 'Full character list';
};
h1_ 'Character summary';
div_ class => 'charsum_list', sub {
@@ -548,7 +548,7 @@ sub charsum_ {
div_ class => 'name', sub {
span_ sub {
abbr_ class => "icons gen $_->{gender}", title => $GENDER{$_->{gender}}, '' if $_->{gender} ne 'unknown';
- a_ href => "/c$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
};
i_ $CHAR_ROLE{$_->{role}}{txt};
};
@@ -556,7 +556,7 @@ sub charsum_ {
txt_ 'Voiced by';
$_->{seiyuu}->@* > 1 ? br_ : txt_ ' ';
join_ \&br_, sub {
- a_ href => "/s$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
+ a_ href => "/$_->{id}", title => $_->{original}||$_->{name}, $_->{name};
b_ class => 'grayedout', $_->{note} if $_->{note};
}, $_->{seiyuu}->@*;
} if $_->{seiyuu}->@*;
@@ -614,12 +614,12 @@ sub stats_ {
txt_ 'Recent votes';
b_ sub {
txt_ '(';
- a_ href => "/v$v->{id}/votes", 'show all';
+ a_ href => "/$v->{id}/votes", 'show all';
txt_ ')';
}
} } };
tfoot_ sub { tr_ sub { td_ colspan => 3, sub {
- a_ href => "/v$v->{id}/reviews#review", sprintf'%d review%s »', $v->{reviews}{total}, $v->{reviews}{total}==1?'':'s';
+ a_ href => "/$v->{id}/reviews#review", sprintf'%d review%s »', $v->{reviews}{total}, $v->{reviews}{total}==1?'':'s';
} } } if $v->{reviews}{total};
tr_ sub {
td_ sub {
@@ -692,7 +692,7 @@ sub screenshots_ {
p_ class => 'rel', sub {
abbr_ class => "icons lang $_", title => $LANGUAGE{$_}, '' for $r->{languages}->@*;
abbr_ class => "icons $_", title => $PLATFORM{$_}, '' for $r->{platforms}->@*;
- a_ href => "/r$r->{id}", $r->{title};
+ a_ href => "/$r->{id}", $r->{title};
};
div_ class => 'scr', sub {
a_ href => imgurl($_->{scr}{id}),
@@ -794,12 +794,12 @@ sub tags_ {
TUWF::get qr{/$RE{vrev}}, sub {
- my $v = db_entry v => tuwf->capture('id'), tuwf->capture('rev');
+ my $v = db_entry tuwf->captures('id', 'rev');
return tuwf->resNotFound if !$v;
enrich_item $v, 1;
- framework_ title => $v->{title}, index => !tuwf->capture('rev'), type => 'v', dbobj => $v, hiddenmsg => 1, js => 1, og => og($v),
+ framework_ title => $v->{title}, index => !tuwf->capture('rev'), dbobj => $v, hiddenmsg => 1, js => 1, og => og($v),
sub {
rev_ $v if tuwf->capture('rev');
infobox_ $v;
@@ -814,12 +814,12 @@ TUWF::get qr{/$RE{vrev}}, sub {
TUWF::get qr{/$RE{vid}/tags}, sub {
- my $v = db_entry v => tuwf->capture('id');
+ my $v = db_entry tuwf->capture('id');
return tuwf->resNotFound if !$v;
enrich_vn $v;
- framework_ title => $v->{title}, index => 1, type => 'v', dbobj => $v, hiddenmsg => 1,
+ framework_ title => $v->{title}, index => 1, dbobj => $v, hiddenmsg => 1,
sub {
infobox_ $v, 1;
tabs_ $v, 'tags';
diff --git a/lib/VNWeb/VN/Tagmod.pm b/lib/VNWeb/VN/Tagmod.pm
index c6af98c4..26abcfd7 100644
--- a/lib/VNWeb/VN/Tagmod.pm
+++ b/lib/VNWeb/VN/Tagmod.pm
@@ -4,7 +4,7 @@ use VNWeb::Prelude;
my $FORM = {
- id => { id => 1 },
+ id => { vndbid => 'v' },
title => { _when => 'out' },
tags => { sort_keys => 'id', aoh => {
id => { id => 1 },
@@ -96,7 +96,7 @@ TUWF::get qr{/$RE{vid}/tagmod}, sub {
$_->{othnotes} = join "\n", map user_displayname($_).': '.$_->{notes}, $_->{othnotes}->@*;
}
- framework_ title => "Edit tags for $v->{title}", type => 'v', dbobj => $v, tab => 'tagmod', sub {
+ framework_ title => "Edit tags for $v->{title}", dbobj => $v, tab => 'tagmod', sub {
elm_ 'Tagmod' => $FORM_OUT, { id => $v->{id}, title => $v->{title}, tags => $tags, mod => auth->permTagmod };
};
};
diff --git a/lib/VNWeb/VN/Votes.pm b/lib/VNWeb/VN/Votes.pm
index c286cb78..a5bce3f7 100644
--- a/lib/VNWeb/VN/Votes.pm
+++ b/lib/VNWeb/VN/Votes.pm
@@ -56,7 +56,7 @@ TUWF::get qr{/$RE{vid}/votes}, sub {
{ a => 'ASC', d => 'DESC' }->{$opt->{o}}
);
- framework_ title => "Votes for $v->{title}", type => 'v', dbobj => $v, sub {
+ framework_ title => "Votes for $v->{title}", dbobj => $v, sub {
div_ class => 'mainbox', sub {
h1_ "Votes for $v->{title}";
p_ 'No votes to list. :(' if !@$lst;
diff --git a/lib/VNWeb/Validation.pm b/lib/VNWeb/Validation.pm
index ec271841..cf95734c 100644
--- a/lib/VNWeb/Validation.pm
+++ b/lib/VNWeb/Validation.pm
@@ -214,7 +214,7 @@ sub validate_dbid {
sub can_edit {
my($type, $entry) = @_;
- return auth->permUsermod || auth->permDbmod || auth->permImgmod || auth->permBoardmod || auth->permTagmod || (auth && $entry->{id} == auth->uid) if $type eq 'u';
+ return auth->permUsermod || auth->permDbmod || auth->permImgmod || auth->permBoardmod || auth->permTagmod || (auth && $entry->{id} eq auth->uid) if $type eq 'u';
return auth->permDbmod if $type eq 'd';
if($type eq 't') {
@@ -229,14 +229,14 @@ sub can_edit {
} else {
die "Can't do authorization test when hidden/date/user_id fields aren't present"
if !exists $entry->{hidden} || !exists $entry->{date} || !exists $entry->{user_id};
- return auth && $entry->{user_id} == auth->uid && !$entry->{hidden} && $entry->{date} > time-config->{board_edit_time};
+ return auth && $entry->{user_id} eq auth->uid && !$entry->{hidden} && $entry->{date} > time-config->{board_edit_time};
}
}
if($type eq 'w') {
return 1 if auth->permBoardmod;
return auth->permReview if !$entry->{id};
- return auth && auth->uid == $entry->{user_id};
+ return auth && auth->uid eq $entry->{user_id};
}
if($type eq 'g' || $type eq 'i') {
diff --git a/sql/data.sql b/sql/data.sql
index 27ba9530..627de164 100644
--- a/sql/data.sql
+++ b/sql/data.sql
@@ -1,4 +1,4 @@
-INSERT INTO users (id, username, mail, notify_dbedit) VALUES (1, 'multi', 'multi@vndb.org', FALSE);
+INSERT INTO users (id, username, mail, notify_dbedit) VALUES ('u1', 'multi', 'multi@vndb.org', FALSE);
SELECT setval('users_id_seq', 2);
INSERT INTO stats_cache (section, count) VALUES
diff --git a/sql/func.sql b/sql/func.sql
index daa52014..988daffb 100644
--- a/sql/func.sql
+++ b/sql/func.sql
@@ -48,7 +48,7 @@ $$ LANGUAGE SQL;
-- update_vncache(id) - updates some c_* columns in the vn table
-CREATE OR REPLACE FUNCTION update_vncache(integer) RETURNS void AS $$
+CREATE OR REPLACE FUNCTION update_vncache(vndbid) RETURNS void AS $$
UPDATE vn SET
c_released = COALESCE((
SELECT MIN(r.released)
@@ -189,7 +189,7 @@ END; $$ LANGUAGE plpgsql;
-- Update users.c_vns, c_votes and c_wish for one user (when given an id) or all users (when given NULL)
-CREATE OR REPLACE FUNCTION update_users_ulist_stats(integer) RETURNS void AS $$
+CREATE OR REPLACE FUNCTION update_users_ulist_stats(vndbid) RETURNS void AS $$
BEGIN
WITH cnt(uid, votes, vns, wish) AS (
SELECT u.id
@@ -212,7 +212,7 @@ $$ LANGUAGE plpgsql; -- Don't use "LANGUAGE SQL" here; Make sure to generate a n
-- When a vid is given, only the tags for that vid will be updated. These
-- incremental updates do not affect tags.c_items, so that may still get
-- out-of-sync.
-CREATE OR REPLACE FUNCTION tag_vn_calc(uvid integer) RETURNS void AS $$
+CREATE OR REPLACE FUNCTION tag_vn_calc(uvid vndbid) RETURNS void AS $$
BEGIN
IF uvid IS NULL THEN
DROP INDEX IF EXISTS tags_vn_inherit_tag_vid;
@@ -262,7 +262,7 @@ $$ LANGUAGE plpgsql SECURITY DEFINER;
-- Recalculate traits_chars. Pretty much same thing as tag_vn_calc().
-CREATE OR REPLACE FUNCTION traits_chars_calc(ucid integer) RETURNS void AS $$
+CREATE OR REPLACE FUNCTION traits_chars_calc(ucid vndbid) RETURNS void AS $$
BEGIN
IF ucid IS NULL THEN
DROP INDEX IF EXISTS traits_chars_tid;
@@ -318,7 +318,7 @@ $$ LANGUAGE plpgsql;
-- Create ulist labels for new users.
-CREATE OR REPLACE FUNCTION ulist_labels_create(integer) RETURNS void AS $$
+CREATE OR REPLACE FUNCTION ulist_labels_create(vndbid) RETURNS void AS $$
INSERT INTO ulist_labels (uid, id, label, private)
VALUES ($1, 1, 'Playing', false),
($1, 2, 'Finished', false),
@@ -337,21 +337,21 @@ $$ LANGUAGE SQL;
-- A MATERIALIZED VIEW would likely be the fastest approach, but keeping that up-to-date seems like a pain.
--
-- Not currently supported: i#, g#, u#, ch#, cv#, sf#
-CREATE OR REPLACE FUNCTION item_info(id vndbid, num int) RETURNS TABLE(title text, uid int) AS $$
+CREATE OR REPLACE FUNCTION item_info(id vndbid, num int) RETURNS TABLE(title text, uid vndbid) AS $$
-- x#.#
- SELECT v.title, h.requester FROM changes h JOIN vn_hist v ON h.id = v.chid WHERE h.type = 'v' AND vndbid_type($1) = 'v' AND h.itemid = vndbid_num($1) AND $2 IS NOT NULL AND h.rev = $2
- UNION ALL SELECT r.title, h.requester FROM changes h JOIN releases_hist r ON h.id = r.chid WHERE h.type = 'r' AND vndbid_type($1) = 'r' AND h.itemid = vndbid_num($1) AND $2 IS NOT NULL AND h.rev = $2
- UNION ALL SELECT p.name, h.requester FROM changes h JOIN producers_hist p ON h.id = p.chid WHERE h.type = 'p' AND vndbid_type($1) = 'p' AND h.itemid = vndbid_num($1) AND $2 IS NOT NULL AND h.rev = $2
- UNION ALL SELECT c.name, h.requester FROM changes h JOIN chars_hist c ON h.id = c.chid WHERE h.type = 'c' AND vndbid_type($1) = 'c' AND h.itemid = vndbid_num($1) AND $2 IS NOT NULL AND h.rev = $2
- UNION ALL SELECT d.title, h.requester FROM changes h JOIN docs_hist d ON h.id = d.chid WHERE h.type = 'd' AND vndbid_type($1) = 'd' AND h.itemid = vndbid_num($1) AND $2 IS NOT NULL AND h.rev = $2
- UNION ALL SELECT sa.name, h.requester FROM changes h JOIN staff_hist s ON h.id = s.chid JOIN staff_alias_hist sa ON sa.chid = s.chid AND sa.aid = s.aid WHERE h.type = 's' AND vndbid_type($1) = 's' AND h.itemid = vndbid_num($1) AND $2 IS NOT NULL AND h.rev = $2
+ SELECT v.title, h.requester FROM changes h JOIN vn_hist v ON h.id = v.chid WHERE vndbid_type($1) = 'v' AND h.itemid = $1 AND $2 IS NOT NULL AND h.rev = $2
+ UNION ALL SELECT r.title, h.requester FROM changes h JOIN releases_hist r ON h.id = r.chid WHERE vndbid_type($1) = 'r' AND h.itemid = $1 AND $2 IS NOT NULL AND h.rev = $2
+ UNION ALL SELECT p.name, h.requester FROM changes h JOIN producers_hist p ON h.id = p.chid WHERE vndbid_type($1) = 'p' AND h.itemid = $1 AND $2 IS NOT NULL AND h.rev = $2
+ UNION ALL SELECT c.name, h.requester FROM changes h JOIN chars_hist c ON h.id = c.chid WHERE vndbid_type($1) = 'c' AND h.itemid = $1 AND $2 IS NOT NULL AND h.rev = $2
+ UNION ALL SELECT d.title, h.requester FROM changes h JOIN docs_hist d ON h.id = d.chid WHERE vndbid_type($1) = 'd' AND h.itemid = $1 AND $2 IS NOT NULL AND h.rev = $2
+ UNION ALL SELECT sa.name, h.requester FROM changes h JOIN staff_hist s ON h.id = s.chid JOIN staff_alias_hist sa ON sa.chid = s.chid AND sa.aid = s.aid WHERE vndbid_type($1) = 's' AND h.itemid = $1 AND $2 IS NOT NULL AND h.rev = $2
-- x#
- UNION ALL SELECT title, NULL FROM vn WHERE vndbid_type($1) = 'v' AND id = vndbid_num($1) AND $2 IS NULL
- UNION ALL SELECT title, NULL FROM releases WHERE vndbid_type($1) = 'r' AND id = vndbid_num($1) AND $2 IS NULL
- UNION ALL SELECT name, NULL FROM producers WHERE vndbid_type($1) = 'p' AND id = vndbid_num($1) AND $2 IS NULL
- UNION ALL SELECT name, NULL FROM chars WHERE vndbid_type($1) = 'c' AND id = vndbid_num($1) AND $2 IS NULL
- UNION ALL SELECT title, NULL FROM docs WHERE vndbid_type($1) = 'd' AND id = vndbid_num($1) AND $2 IS NULL
- UNION ALL SELECT sa.name, NULL FROM staff s JOIN staff_alias sa ON sa.aid = s.aid WHERE vndbid_type($1) = 's' AND s.id = vndbid_num($1) AND $2 IS NOT NULL AND $2 IS NULL
+ UNION ALL SELECT title, NULL FROM vn WHERE vndbid_type($1) = 'v' AND id = $1 AND $2 IS NULL
+ UNION ALL SELECT title, NULL FROM releases WHERE vndbid_type($1) = 'r' AND id = $1 AND $2 IS NULL
+ UNION ALL SELECT name, NULL FROM producers WHERE vndbid_type($1) = 'p' AND id = $1 AND $2 IS NULL
+ UNION ALL SELECT name, NULL FROM chars WHERE vndbid_type($1) = 'c' AND id = $1 AND $2 IS NULL
+ UNION ALL SELECT title, NULL FROM docs WHERE vndbid_type($1) = 'd' AND id = $1 AND $2 IS NULL
+ UNION ALL SELECT sa.name, NULL FROM staff s JOIN staff_alias sa ON sa.aid = s.aid WHERE vndbid_type($1) = 's' AND s.id = $1 AND $2 IS NOT NULL AND $2 IS NULL
-- t#
UNION ALL SELECT title, NULL FROM threads WHERE vndbid_type($1) = 't' AND id = $1 AND $2 IS NULL
-- t#.#
@@ -372,16 +372,14 @@ $$ LANGUAGE SQL ROWS 1;
-- The two functions below are utility functions used by the item-specific functions in editfunc.sql
-- create temporary table for generic revision info, and returns the chid of the revision being edited (or NULL).
-CREATE OR REPLACE FUNCTION edit_revtable(xtype dbentry_type, xitemid integer, xrev integer) RETURNS integer AS $$
+CREATE OR REPLACE FUNCTION edit_revtable(xitemid vndbid, xrev integer) RETURNS integer AS $$
DECLARE
- ret integer;
x record;
BEGIN
BEGIN
CREATE TEMPORARY TABLE edit_revision (
- type dbentry_type NOT NULL,
- itemid integer,
- requester integer,
+ itemid vndbid,
+ requester vndbid,
ip inet,
comments text,
ihid boolean,
@@ -390,61 +388,30 @@ BEGIN
EXCEPTION WHEN duplicate_table THEN
TRUNCATE edit_revision;
END;
- SELECT INTO x id, ihid, ilock FROM changes c WHERE type = xtype AND itemid = xitemid AND rev = xrev;
- INSERT INTO edit_revision (type, itemid, ihid, ilock) VALUES (xtype, xitemid, COALESCE(x.ihid, FALSE), COALESCE(x.ilock, FALSE));
+ SELECT INTO x id, ihid, ilock FROM changes c WHERE itemid = xitemid AND rev = xrev;
+ INSERT INTO edit_revision (itemid, ihid, ilock) VALUES (xitemid, COALESCE(x.ihid, FALSE), COALESCE(x.ilock, FALSE));
RETURN x.id;
END;
$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION edit_commit() RETURNS edit_rettype AS $$
-DECLARE
- ret edit_rettype;
- xtype dbentry_type;
-BEGIN
- SELECT type INTO xtype FROM edit_revision;
- SELECT itemid INTO ret.itemid FROM edit_revision;
- -- figure out revision number
- SELECT MAX(rev)+1 INTO ret.rev FROM changes WHERE type = xtype AND itemid = ret.itemid;
- SELECT COALESCE(ret.rev, 1) INTO ret.rev;
- -- insert DB item
- IF ret.itemid IS NULL THEN
- CASE xtype
- WHEN 'v' THEN INSERT INTO vn DEFAULT VALUES RETURNING id INTO ret.itemid;
- WHEN 'r' THEN INSERT INTO releases DEFAULT VALUES RETURNING id INTO ret.itemid;
- WHEN 'p' THEN INSERT INTO producers DEFAULT VALUES RETURNING id INTO ret.itemid;
- WHEN 'c' THEN INSERT INTO chars DEFAULT VALUES RETURNING id INTO ret.itemid;
- WHEN 's' THEN INSERT INTO staff DEFAULT VALUES RETURNING id INTO ret.itemid;
- WHEN 'd' THEN INSERT INTO docs DEFAULT VALUES RETURNING id INTO ret.itemid;
- END CASE;
- END IF;
- -- insert change
- INSERT INTO changes (type, itemid, rev, requester, ip, comments, ihid, ilock)
- SELECT type, ret.itemid, ret.rev, requester, ip, comments, ihid, ilock FROM edit_revision RETURNING id INTO ret.chid;
- RETURN ret;
-END;
-$$ LANGUAGE plpgsql;
-
-
-
-- Check for stuff to be done when an item has been changed
-CREATE OR REPLACE FUNCTION edit_committed(xtype dbentry_type, xedit edit_rettype) RETURNS void AS $$
+CREATE OR REPLACE FUNCTION edit_committed(nchid integer, nitemid vndbid, nrev integer) RETURNS void AS $$
DECLARE
xoldchid integer;
BEGIN
- SELECT id INTO xoldchid FROM changes WHERE type = xtype AND itemid = xedit.itemid AND rev = xedit.rev-1;
+ SELECT id INTO xoldchid FROM changes WHERE itemid = nitemid AND rev = nrev-1;
-- Set c_search to NULL and notify when
-- 1. A new VN entry is created
-- 2. The vn title/original/alias has changed
- IF xtype = 'v' THEN
+ IF vndbid_type(nitemid) = 'v' THEN
IF -- 1.
xoldchid IS NULL OR
-- 2.
- EXISTS(SELECT 1 FROM vn_hist v1, vn_hist v2 WHERE (v2.title <> v1.title OR v2.original <> v1.original OR v2.alias <> v1.alias) AND v1.chid = xoldchid AND v2.chid = xedit.chid)
+ EXISTS(SELECT 1 FROM vn_hist v1, vn_hist v2 WHERE (v2.title <> v1.title OR v2.original <> v1.original OR v2.alias <> v1.alias) AND v1.chid = xoldchid AND v2.chid = nchid)
THEN
- UPDATE vn SET c_search = NULL WHERE id = xedit.itemid;
+ UPDATE vn SET c_search = NULL WHERE id = nitemid;
NOTIFY vnsearch;
END IF;
END IF;
@@ -454,58 +421,58 @@ BEGIN
-- 2. A release has been hidden or unhidden
-- 3. The release title/original has changed
-- 4. The releases_vn table differs from a previous revision
- IF xtype = 'r' THEN
+ IF vndbid_type(nitemid) = 'r' THEN
IF -- 1.
xoldchid IS NULL OR
-- 2.
- EXISTS(SELECT 1 FROM changes c1, changes c2 WHERE c1.ihid IS DISTINCT FROM c2.ihid AND c1.id = xedit.chid AND c2.id = xoldchid) OR
+ EXISTS(SELECT 1 FROM changes c1, changes c2 WHERE c1.ihid IS DISTINCT FROM c2.ihid AND c1.id = nchid AND c2.id = xoldchid) OR
-- 3.
- EXISTS(SELECT 1 FROM releases_hist r1, releases_hist r2 WHERE (r2.title <> r1.title OR r2.original <> r1.original) AND r1.chid = xoldchid AND r2.chid = xedit.chid) OR
+ EXISTS(SELECT 1 FROM releases_hist r1, releases_hist r2 WHERE (r2.title <> r1.title OR r2.original <> r1.original) AND r1.chid = xoldchid AND r2.chid = nchid) OR
-- 4.
- EXISTS(SELECT vid FROM releases_vn_hist WHERE chid = xoldchid EXCEPT SELECT vid FROM releases_vn_hist WHERE chid = xedit.chid) OR
- EXISTS(SELECT vid FROM releases_vn_hist WHERE chid = xedit.chid EXCEPT SELECT vid FROM releases_vn_hist WHERE chid = xoldchid)
+ EXISTS(SELECT vid FROM releases_vn_hist WHERE chid = xoldchid EXCEPT SELECT vid FROM releases_vn_hist WHERE chid = nchid) OR
+ EXISTS(SELECT vid FROM releases_vn_hist WHERE chid = nchid EXCEPT SELECT vid FROM releases_vn_hist WHERE chid = xoldchid)
THEN
- UPDATE vn SET c_search = NULL WHERE id IN(SELECT vid FROM releases_vn_hist WHERE chid IN(xedit.chid, xoldchid));
+ UPDATE vn SET c_search = NULL WHERE id IN(SELECT vid FROM releases_vn_hist WHERE chid IN(nchid, xoldchid));
NOTIFY vnsearch;
END IF;
END IF;
-- Call update_vncache() for related VNs when a release has been created or edited
-- (This could be made more specific, but update_vncache() is fast enough that it's not worth the complexity)
- IF xtype = 'r' THEN
+ IF vndbid_type(nitemid) = 'r' THEN
PERFORM update_vncache(vid) FROM (
- SELECT DISTINCT vid FROM releases_vn_hist WHERE chid IN(xedit.chid, xoldchid)
+ SELECT DISTINCT vid FROM releases_vn_hist WHERE chid IN(nchid, xoldchid)
) AS v(vid);
END IF;
-- Call traits_chars_calc() for characters to update the traits cache
- IF xtype = 'c' THEN
- PERFORM traits_chars_calc(xedit.itemid);
+ IF vndbid_type(nitemid) = 'c' THEN
+ PERFORM traits_chars_calc(nitemid);
END IF;
-- Create edit notifications
INSERT INTO notifications (uid, ntype, iid, num)
- SELECT n.uid, n.ntype, n.iid, n.num FROM changes c, notify(vndbid(c.type::text, c.itemid), c.rev, c.requester) n WHERE c.id = xedit.chid;
+ SELECT n.uid, n.ntype, n.iid, n.num FROM changes c, notify(nitemid, c.rev, c.requester) n WHERE c.id = nchid;
-- Make sure all visual novels linked to a release have a corresponding entry
-- in ulist_vns for users who have the release in rlists. This is action (3) in
-- update_vnlist_rlist().
- IF xtype = 'r' AND xoldchid IS NOT NULL
+ IF vndbid_type(nitemid) = 'r' AND xoldchid IS NOT NULL
THEN
INSERT INTO ulist_vns (uid, vid)
- SELECT rl.uid, rv.vid FROM rlists rl JOIN releases_vn rv ON rv.id = rl.rid WHERE rl.rid = xedit.itemid
+ SELECT rl.uid, rv.vid FROM rlists rl JOIN releases_vn rv ON rv.id = rl.rid WHERE rl.rid = nitemid
ON CONFLICT (uid, vid) DO NOTHING;
END IF;
-- Call update_images_cache() where appropriate
- IF xtype = 'c'
+ IF vndbid_type(nitemid) = 'c'
THEN
- PERFORM update_images_cache(image) FROM chars_hist WHERE chid IN(xoldchid,xedit.chid) AND image IS NOT NULL;
+ PERFORM update_images_cache(image) FROM chars_hist WHERE chid IN(xoldchid,nchid) AND image IS NOT NULL;
END IF;
- IF xtype = 'v'
+ IF vndbid_type(nitemid) = 'v'
THEN
- PERFORM update_images_cache(image) FROM vn_hist WHERE chid IN(xoldchid,xedit.chid) AND image IS NOT NULL;
- PERFORM update_images_cache(scr) FROM vn_screenshots_hist WHERE chid IN(xoldchid,xedit.chid);
+ PERFORM update_images_cache(image) FROM vn_hist WHERE chid IN(xoldchid,nchid) AND image IS NOT NULL;
+ PERFORM update_images_cache(scr) FROM vn_screenshots_hist WHERE chid IN(xoldchid,nchid);
END IF;
END;
$$ LANGUAGE plpgsql;
@@ -522,7 +489,7 @@ $$ LANGUAGE plpgsql;
-- 'iid' and 'num' identify the item that has been created.
-- 'uid' indicates who created the item, providing an easy method of not creating a notification for that user.
-- (can technically be fetched with a DB lookup, too)
-CREATE OR REPLACE FUNCTION notify(iid vndbid, num integer, uid integer) RETURNS TABLE (uid integer, ntype notification_ntype[], iid vndbid, num int) AS $$
+CREATE OR REPLACE FUNCTION notify(iid vndbid, num integer, uid vndbid) RETURNS TABLE (uid vndbid, ntype notification_ntype[], iid vndbid, num int) AS $$
SELECT uid, array_agg(ntype), $1, $2
FROM (
@@ -536,9 +503,9 @@ CREATE OR REPLACE FUNCTION notify(iid vndbid, num integer, uid integer) RETURNS
UNION
SELECT 'dbdel', c_all.requester
FROM changes c_cur, changes c_all, changes c_pre
- WHERE c_cur.type = vndbid_type($1)::dbentry_type AND c_cur.itemid = vndbid_num($1) AND c_cur.rev = $2 -- Current edit
- AND c_pre.type = vndbid_type($1)::dbentry_type AND c_pre.itemid = vndbid_num($1) AND c_pre.rev = $2-1 -- Previous edit, to check if .ihid changed
- AND c_all.type = vndbid_type($1)::dbentry_type AND c_all.itemid = vndbid_num($1) -- All edits on this entry, to see whom to notify
+ WHERE c_cur.itemid = $1 AND c_cur.rev = $2 -- Current edit
+ AND c_pre.itemid = $1 AND c_pre.rev = $2-1 -- Previous edit, to check if .ihid changed
+ AND c_all.itemid = $1 -- All edits on this entry, to see whom to notify
AND c_cur.ihid AND NOT c_pre.ihid
AND $2 > 1 AND vndbid_type($1) IN('v', 'r', 'p', 'c', 's', 'd')
@@ -546,12 +513,12 @@ CREATE OR REPLACE FUNCTION notify(iid vndbid, num integer, uid integer) RETURNS
UNION
SELECT 'listdel', u.uid
FROM changes c_cur, changes c_pre,
- ( SELECT uid FROM ulist_vns WHERE vndbid_type($1) = 'v' AND vid = vndbid_num($1) -- TODO: Could use an index on ulist_vns.vid
+ ( SELECT uid FROM ulist_vns WHERE vndbid_type($1) = 'v' AND vid = $1 -- TODO: Could use an index on ulist_vns.vid
UNION ALL
- SELECT uid FROM rlists WHERE vndbid_type($1) = 'r' AND rid = vndbid_num($1) -- TODO: Could also use an index, but the rlists table isn't that large so it's still okay
+ SELECT uid FROM rlists WHERE vndbid_type($1) = 'r' AND rid = $1 -- TODO: Could also use an index, but the rlists table isn't that large so it's still okay
) u(uid)
- WHERE c_cur.type = vndbid_type($1)::dbentry_type AND c_cur.itemid = vndbid_num($1) AND c_cur.rev = $2 -- Current edit
- AND c_pre.type = vndbid_type($1)::dbentry_type AND c_pre.itemid = vndbid_num($1) AND c_pre.rev = $2-1 -- Previous edit, to check if .ihid changed
+ WHERE c_cur.itemid = $1 AND c_cur.rev = $2 -- Current edit
+ AND c_pre.itemid = $1 AND c_pre.rev = $2-1 -- Previous edit, to check if .ihid changed
AND c_cur.ihid AND NOT c_pre.ihid
AND $2 > 1 AND vndbid_type($1) IN('v','r')
@@ -560,9 +527,9 @@ CREATE OR REPLACE FUNCTION notify(iid vndbid, num integer, uid integer) RETURNS
SELECT 'dbedit', c.requester
FROM changes c
JOIN users u ON u.id = c.requester
- WHERE c.type = vndbid_type($1)::dbentry_type AND c.itemid = vndbid_num($1)
+ WHERE c.itemid = $1
AND $2 > 1 AND vndbid_type($1) IN('v', 'r', 'p', 'c', 's', 'd')
- AND $3 <> 1 -- Exclude edits by Multi
+ AND $3 <> 'u1' -- Exclude edits by Multi
AND u.notify_dbedit
AND NOT EXISTS(SELECT 1 FROM notification_subs ns WHERE ns.iid = $1 AND ns.uid = c.requester AND ns.subnum = false)
@@ -571,7 +538,7 @@ CREATE OR REPLACE FUNCTION notify(iid vndbid, num integer, uid integer) RETURNS
SELECT 'subedit', ns.uid
FROM notification_subs ns
WHERE $2 > 1 AND vndbid_type($1) IN('v', 'r', 'p', 'c', 's', 'd')
- AND $3 <> 1 -- Exclude edits by Multi
+ AND $3 <> 'u1' -- Exclude edits by Multi
AND ns.iid = $1 AND ns.subnum
-- announce
@@ -622,7 +589,7 @@ CREATE OR REPLACE FUNCTION notify(iid vndbid, num integer, uid integer) RETURNS
UNION
SELECT 'subreview', ns.uid
FROM reviews w, notification_subs ns
- WHERE w.id = $1 AND vndbid_type($1) = 'w' AND $2 IS NULL AND ns.iid = vndbid('v', w.vid) AND ns.subreview
+ WHERE w.id = $1 AND vndbid_type($1) = 'w' AND $2 IS NULL AND ns.iid = w.vid AND ns.subreview
-- subapply
UNION
@@ -630,14 +597,14 @@ CREATE OR REPLACE FUNCTION notify(iid vndbid, num integer, uid integer) RETURNS
FROM notification_subs
WHERE subapply AND vndbid_type($1) = 'c' AND $2 IS NOT NULL
AND iid IN(
- WITH new(tid) AS (SELECT vndbid('i', tid) FROM chars_traits_hist WHERE chid = (SELECT id FROM changes WHERE type = 'c' AND itemid = vndbid_num($1) AND rev = $2)),
- old(tid) AS (SELECT vndbid('i', tid) FROM chars_traits_hist WHERE chid = (SELECT id FROM changes WHERE type = 'c' AND itemid = vndbid_num($1) AND $2 > 1 AND rev = $2-1))
+ WITH new(tid) AS (SELECT vndbid('i', tid) FROM chars_traits_hist WHERE chid = (SELECT id FROM changes WHERE itemid = $1 AND rev = $2)),
+ old(tid) AS (SELECT vndbid('i', tid) FROM chars_traits_hist WHERE chid = (SELECT id FROM changes WHERE itemid = $1 AND $2 > 1 AND rev = $2-1))
(SELECT tid FROM old EXCEPT SELECT tid FROM new) UNION (SELECT tid FROM new EXCEPT SELECT tid FROM old)
)
) AS noti(ntype, uid)
WHERE uid <> $3
- AND uid <> 1 -- No announcements for Multi
+ AND uid <> 'u1' -- No announcements for Multi
GROUP BY uid;
$$ LANGUAGE SQL;
@@ -653,7 +620,7 @@ $$ LANGUAGE SQL;
-- Returns the raw scrypt parameters (N, r, p and salt) for this user, in order
-- to create an encrypted pass. Returns NULL if this user does not have a valid
-- password.
-CREATE OR REPLACE FUNCTION user_getscryptargs(integer) RETURNS bytea AS $$
+CREATE OR REPLACE FUNCTION user_getscryptargs(vndbid) RETURNS bytea AS $$
SELECT
CASE WHEN length(passwd) = 46 THEN substring(passwd from 1 for 14) ELSE NULL END
FROM users WHERE id = $1
@@ -661,7 +628,7 @@ $$ LANGUAGE SQL SECURITY DEFINER;
-- Create a new web session for this user (uid, scryptpass, token)
-CREATE OR REPLACE FUNCTION user_login(integer, bytea, bytea) RETURNS boolean AS $$
+CREATE OR REPLACE FUNCTION user_login(vndbid, bytea, bytea) RETURNS boolean AS $$
INSERT INTO sessions (uid, token, expires, type) SELECT $1, $3, NOW() + '1 month', 'web' FROM users
WHERE length($2) = 46 AND length($3) = 20
AND id = $1 AND passwd = $2
@@ -669,14 +636,14 @@ CREATE OR REPLACE FUNCTION user_login(integer, bytea, bytea) RETURNS boolean AS
$$ LANGUAGE SQL SECURITY DEFINER;
-CREATE OR REPLACE FUNCTION user_logout(integer, bytea) RETURNS void AS $$
+CREATE OR REPLACE FUNCTION user_logout(vndbid, bytea) RETURNS void AS $$
DELETE FROM sessions WHERE uid = $1 AND token = $2 AND type = 'web'
$$ LANGUAGE SQL SECURITY DEFINER;
-- Returns true if the given session token is valid.
-- As a side effect, this also extends the expiration time of web sessions.
-CREATE OR REPLACE FUNCTION user_isvalidsession(integer, bytea, session_type) RETURNS bool AS $$
+CREATE OR REPLACE FUNCTION user_isvalidsession(vndbid, bytea, session_type) RETURNS bool AS $$
UPDATE sessions SET expires = NOW() + '1 month'
WHERE uid = $1 AND token = $2 AND type = $3 AND $3 = 'web'
AND expires < NOW() + '1 month'::interval - '6 hours'::interval;
@@ -685,7 +652,7 @@ $$ LANGUAGE SQL SECURITY DEFINER;
-- Used for duplicate email checks and user-by-email lookup for usermods.
-CREATE OR REPLACE FUNCTION user_emailtoid(text) RETURNS SETOF integer AS $$
+CREATE OR REPLACE FUNCTION user_emailtoid(text) RETURNS SETOF vndbid AS $$
SELECT id FROM users WHERE lower(mail) = lower($1)
$$ LANGUAGE SQL SECURITY DEFINER;
@@ -696,7 +663,7 @@ $$ LANGUAGE SQL SECURITY DEFINER;
-- Ideally Postgres itself would send the user an email so that the application
-- calling this function doesn't even get the token, and thus can't get access
-- to someone's account. But alas, that'd require a separate process.
-CREATE OR REPLACE FUNCTION user_resetpass(text, bytea) RETURNS integer AS $$
+CREATE OR REPLACE FUNCTION user_resetpass(text, bytea) RETURNS vndbid AS $$
INSERT INTO sessions (uid, token, expires, type)
SELECT id, $2, NOW()+'1 week', 'pass' FROM users
WHERE lower(mail) = lower($1) AND length($2) = 20 AND NOT perm_usermod
@@ -705,7 +672,7 @@ $$ LANGUAGE SQL SECURITY DEFINER;
-- Changes the user's password and invalidates all existing sessions. args: uid, old_pass_or_reset_token, new_pass
-CREATE OR REPLACE FUNCTION user_setpass(integer, bytea, bytea) RETURNS boolean AS $$
+CREATE OR REPLACE FUNCTION user_setpass(vndbid, bytea, bytea) RETURNS boolean AS $$
WITH upd(id) AS (
UPDATE users SET passwd = $3
WHERE id = $1
@@ -723,24 +690,24 @@ $$ LANGUAGE SQL SECURITY DEFINER;
-- Internal function, used to verify whether user ($2 with session $3) is
-- allowed to access sensitive data from user $1.
-CREATE OR REPLACE FUNCTION user_isauth(integer, integer, bytea) RETURNS boolean AS $$
+CREATE OR REPLACE FUNCTION user_isauth(vndbid, vndbid, bytea) RETURNS boolean AS $$
SELECT true FROM users
WHERE id = $2
AND EXISTS(SELECT 1 FROM sessions WHERE uid = $2 AND token = $3 AND type = 'web')
- AND ($2 = $1 OR perm_usermod)
+ AND ($2 IS NOT DISTINCT FROM $1 OR perm_usermod)
$$ LANGUAGE SQL;
-- uid of user email to get, uid currently logged in, session token of currently logged in.
-- Ensures that only the user itself or a useradmin can get someone's email address.
-CREATE OR REPLACE FUNCTION user_getmail(integer, integer, bytea) RETURNS text AS $$
+CREATE OR REPLACE FUNCTION user_getmail(vndbid, vndbid, bytea) RETURNS text AS $$
SELECT mail FROM users WHERE id = $1 AND user_isauth($1, $2, $3)
$$ LANGUAGE SQL SECURITY DEFINER;
-- Set a token to change a user's email address.
-- Args: uid, web-token, new-email-token, email
-CREATE OR REPLACE FUNCTION user_setmail_token(integer, bytea, bytea, text) RETURNS void AS $$
+CREATE OR REPLACE FUNCTION user_setmail_token(vndbid, bytea, bytea, text) RETURNS void AS $$
INSERT INTO sessions (uid, token, expires, type, mail)
SELECT id, $3, NOW()+'1 week', 'mail', $4 FROM users
WHERE id = $1 AND user_isauth($1, $1, $2) AND length($3) = 20
@@ -748,7 +715,7 @@ $$ LANGUAGE SQL SECURITY DEFINER;
-- Actually change a user's email address, given a valid token.
-CREATE OR REPLACE FUNCTION user_setmail_confirm(integer, bytea) RETURNS boolean AS $$
+CREATE OR REPLACE FUNCTION user_setmail_confirm(vndbid, bytea) RETURNS boolean AS $$
WITH u(mail) AS (
DELETE FROM sessions WHERE uid = $1 AND token = $2 AND type = 'mail' AND expires > NOW() RETURNING mail
)
@@ -756,19 +723,19 @@ CREATE OR REPLACE FUNCTION user_setmail_confirm(integer, bytea) RETURNS boolean
$$ LANGUAGE SQL SECURITY DEFINER;
-CREATE OR REPLACE FUNCTION user_setperm_usermod(integer, integer, bytea, boolean) RETURNS void AS $$
- UPDATE users SET perm_usermod = $4 WHERE id = $1 AND user_isauth(-1, $2, $3)
+CREATE OR REPLACE FUNCTION user_setperm_usermod(vndbid, vndbid, bytea, boolean) RETURNS void AS $$
+ UPDATE users SET perm_usermod = $4 WHERE id = $1 AND user_isauth(NULL, $2, $3)
$$ LANGUAGE SQL SECURITY DEFINER;
-CREATE OR REPLACE FUNCTION user_admin_setpass(integer, integer, bytea, bytea) RETURNS void AS $$
+CREATE OR REPLACE FUNCTION user_admin_setpass(vndbid, vndbid, bytea, bytea) RETURNS void AS $$
WITH upd(id) AS (
- UPDATE users SET passwd = $4 WHERE id = $1 AND user_isauth(-1, $2, $3) AND length($4) = 46 RETURNING id
+ UPDATE users SET passwd = $4 WHERE id = $1 AND user_isauth(NULL, $2, $3) AND length($4) = 46 RETURNING id
)
DELETE FROM sessions WHERE uid IN(SELECT id FROM upd)
$$ LANGUAGE SQL SECURITY DEFINER;
-CREATE OR REPLACE FUNCTION user_admin_setmail(integer, integer, bytea, text) RETURNS void AS $$
- UPDATE users SET mail = $4 WHERE id = $1 AND user_isauth(-1, $2, $3)
+CREATE OR REPLACE FUNCTION user_admin_setmail(vndbid, vndbid, bytea, text) RETURNS void AS $$
+ UPDATE users SET mail = $4 WHERE id = $1 AND user_isauth(NULL, $2, $3)
$$ LANGUAGE SQL SECURITY DEFINER;
diff --git a/sql/schema.sql b/sql/schema.sql
index dadc5f65..fd512332 100644
--- a/sql/schema.sql
+++ b/sql/schema.sql
@@ -1,7 +1,7 @@
-- Convention for database items with version control:
--
-- CREATE TABLE items ( -- dbentry_type=x
--- id SERIAL PRIMARY KEY,
+-- id vndbid NOT NULL PRIMARY KEY ..,
-- locked boolean NOT NULL DEFAULT FALSE,
-- hidden boolean NOT NULL DEFAULT FALSE,
-- -- item-specific columns here
@@ -21,7 +21,7 @@
-- item-related tables work roughly the same:
--
-- CREATE TABLE items_field (
--- id integer, -- references items.id
+-- id vndbid, -- references items.id
-- -- field-specific columns here
-- );
-- CREATE TABLE items_field_hist ( -- History of the 'items_field' table
@@ -53,7 +53,6 @@ CREATE TYPE char_role AS ENUM ('main', 'primary', 'side', 'appears');
CREATE TYPE credit_type AS ENUM ('scenario', 'chardesign', 'art', 'music', 'songs', 'director', 'staff');
CREATE TYPE cup_size AS ENUM ('', 'AAA', 'AA', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z');
CREATE TYPE dbentry_type AS ENUM ('v', 'r', 'p', 'c', 's', 'd');
-CREATE TYPE edit_rettype AS (itemid integer, chid integer, rev integer);
CREATE TYPE gender AS ENUM ('unknown', 'm', 'f', 'b');
CREATE TYPE language AS ENUM ('ar', 'bg', 'ca', 'cs', 'da', 'de', 'el', 'en', 'eo', 'es', 'fa', 'fi', 'fr', 'ga', 'gd', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'mk', 'ms', 'lt', 'lv', 'nl', 'no', 'pl', 'pt-pt', 'pt-br', 'ro', 'ru', 'sk', 'sl', 'sv', 'ta', 'th', 'tr', 'uk', 'vi', 'zh');
CREATE TYPE medium AS ENUM ('cd', 'dvd', 'gdr', 'blr', 'flp', 'mrt', 'mem', 'umd', 'nod', 'in', 'otc');
@@ -69,10 +68,17 @@ CREATE TYPE session_type AS ENUM ('web', 'pass', 'mail');
-- Sequences used for ID generation
CREATE SEQUENCE charimg_seq;
+CREATE SEQUENCE chars_id_seq;
CREATE SEQUENCE covers_seq;
+CREATE SEQUENCE docs_id_seq;
+CREATE SEQUENCE producers_id_seq;
+CREATE SEQUENCE releases_id_seq;
CREATE SEQUENCE reviews_seq;
CREATE SEQUENCE screenshots_seq;
+CREATE SEQUENCE staff_id_seq;
CREATE SEQUENCE threads_id_seq;
+CREATE SEQUENCE vn_id_seq;
+CREATE SEQUENCE users_id_seq;
@@ -91,8 +97,8 @@ CREATE TABLE anime (
-- audit_log
CREATE TABLE audit_log (
date timestamptz NOT NULL DEFAULT NOW(),
- by_uid integer,
- affected_uid integer,
+ by_uid vndbid,
+ affected_uid vndbid,
by_ip inet NOT NULL,
by_name text,
affected_name text,
@@ -103,10 +109,9 @@ CREATE TABLE audit_log (
-- changes
CREATE TABLE changes (
id SERIAL PRIMARY KEY,
- requester integer,
+ requester vndbid,
added timestamptz NOT NULL DEFAULT NOW(),
- type dbentry_type NOT NULL,
- itemid integer NOT NULL,
+ itemid vndbid NOT NULL,
rev integer NOT NULL DEFAULT 1,
ihid boolean NOT NULL DEFAULT FALSE,
ilock boolean NOT NULL DEFAULT FALSE,
@@ -116,13 +121,13 @@ CREATE TABLE changes (
-- chars
CREATE TABLE chars ( -- dbentry_type=c
- id SERIAL PRIMARY KEY, -- [pub]
+ id vndbid NOT NULL PRIMARY KEY DEFAULT vndbid('c', nextval('chars_id_seq')::int) CONSTRAINT chars_id_check CHECK(vndbid_type(id) = 'c'), -- [pub]
image vndbid CONSTRAINT chars_image_check CHECK(vndbid_type(image) = 'ch'), -- [pub]
gender gender NOT NULL DEFAULT 'unknown', -- [pub]
spoil_gender gender, -- [pub]
bloodt blood_type NOT NULL DEFAULT 'unknown', -- [pub]
cup_size cup_size NOT NULL DEFAULT '', -- [pub]
- main integer, -- [pub] chars.id
+ main vndbid, -- [pub] chars.id
s_bust smallint NOT NULL DEFAULT 0, -- [pub]
s_waist smallint NOT NULL DEFAULT 0, -- [pub]
s_hip smallint NOT NULL DEFAULT 0, -- [pub]
@@ -148,7 +153,7 @@ CREATE TABLE chars_hist (
spoil_gender gender,
bloodt blood_type NOT NULL DEFAULT 'unknown',
cup_size cup_size NOT NULL DEFAULT '',
- main integer, -- chars.id
+ main vndbid, -- chars.id
s_bust smallint NOT NULL DEFAULT 0,
s_waist smallint NOT NULL DEFAULT 0,
s_hip smallint NOT NULL DEFAULT 0,
@@ -166,7 +171,7 @@ CREATE TABLE chars_hist (
-- chars_traits
CREATE TABLE chars_traits (
- id integer NOT NULL, -- [pub]
+ id vndbid NOT NULL, -- [pub]
tid integer NOT NULL, -- [pub] traits.id
spoil smallint NOT NULL DEFAULT 0, -- [pub]
PRIMARY KEY(id, tid)
@@ -182,9 +187,9 @@ CREATE TABLE chars_traits_hist (
-- chars_vns
CREATE TABLE chars_vns (
- id integer NOT NULL, -- [pub]
- vid integer NOT NULL, -- [pub] vn.id
- rid integer NULL, -- [pub] releases.id
+ id vndbid NOT NULL, -- [pub]
+ vid vndbid NOT NULL, -- [pub] vn.id
+ rid vndbid NULL, -- [pub] releases.id
role char_role NOT NULL DEFAULT 'main', -- [pub]
spoil smallint NOT NULL DEFAULT 0 -- [pub]
);
@@ -192,15 +197,15 @@ CREATE TABLE chars_vns (
-- chars_vns_hist
CREATE TABLE chars_vns_hist (
chid integer NOT NULL,
- vid integer NOT NULL, -- vn.id
- rid integer NULL, -- releases.id
+ vid vndbid NOT NULL, -- vn.id
+ rid vndbid NULL, -- releases.id
role char_role NOT NULL DEFAULT 'main',
spoil smallint NOT NULL DEFAULT 0
);
-- docs
CREATE TABLE docs ( -- dbentry_type=d
- id SERIAL PRIMARY KEY, -- [pub]
+ id vndbid NOT NULL PRIMARY KEY DEFAULT vndbid('d', nextval('docs_id_seq')::int) CONSTRAINT docs_id_check CHECK(vndbid_type(id) = 'd') , -- [pub]
locked boolean NOT NULL DEFAULT FALSE,
hidden boolean NOT NULL DEFAULT FALSE,
title varchar(200) NOT NULL DEFAULT '', -- [pub]
@@ -227,13 +232,13 @@ CREATE TABLE images (
c_violence_avg real, -- [pub]
c_violence_stddev real, -- [pub]
c_weight real NOT NULL DEFAULT 0, -- [pub]
- c_uids integer[] NOT NULL DEFAULT '{}'
+ c_uids vndbid[] NOT NULL DEFAULT '{}'
);
-- image_votes
CREATE TABLE image_votes (
id vndbid NOT NULL, -- [pub]
- uid integer, -- [pub]
+ uid vndbid, -- [pub]
date timestamptz NOT NULL DEFAULT NOW(),-- [pub]
sexual smallint NOT NULL CHECK(sexual >= 0 AND sexual <= 2), -- [pub]
violence smallint NOT NULL CHECK(violence >= 0 AND violence <= 2), -- [pub]
@@ -248,7 +253,7 @@ CREATE TABLE login_throttle (
-- notification_subs
CREATE TABLE notification_subs (
- uid integer NOT NULL,
+ uid vndbid NOT NULL,
iid vndbid NOT NULL,
-- Indicates a subscription on the creation of a new 'num' for the item, i.e. new post, new comment, new edit.
-- Affects the following ntypes: dbedit, subedit, pm, post, comment, subpost. Does not affect: dbdel, listdel.
@@ -264,7 +269,7 @@ CREATE TABLE notification_subs (
-- notifications
CREATE TABLE notifications (
id serial PRIMARY KEY,
- uid integer NOT NULL,
+ uid vndbid NOT NULL,
date timestamptz NOT NULL DEFAULT NOW(),
read timestamptz,
iid vndbid NOT NULL,
@@ -274,7 +279,7 @@ CREATE TABLE notifications (
-- producers
CREATE TABLE producers ( -- dbentry_type=p
- id SERIAL PRIMARY KEY, -- [pub]
+ id vndbid NOT NULL PRIMARY KEY DEFAULT vndbid('p', nextval('producers_id_seq')::int) CONSTRAINT producers_id_check CHECK(vndbid_type(id) = 'p'), -- [pub]
type producer_type NOT NULL DEFAULT 'co', -- [pub]
lang language NOT NULL DEFAULT 'ja', -- [pub]
l_wikidata integer, -- [pub]
@@ -304,8 +309,8 @@ CREATE TABLE producers_hist (
-- producers_relations
CREATE TABLE producers_relations (
- id integer NOT NULL, -- [pub]
- pid integer NOT NULL, -- [pub] producers.id
+ id vndbid NOT NULL, -- [pub]
+ pid vndbid NOT NULL, -- [pub] producers.id
relation producer_relation NOT NULL, -- [pub]
PRIMARY KEY(id, pid)
);
@@ -313,21 +318,21 @@ CREATE TABLE producers_relations (
-- producers_relations_hist
CREATE TABLE producers_relations_hist (
chid integer NOT NULL,
- pid integer NOT NULL, -- producers.id
+ pid vndbid NOT NULL, -- producers.id
relation producer_relation NOT NULL,
PRIMARY KEY(chid, pid)
);
-- quotes
CREATE TABLE quotes (
- vid integer NOT NULL, -- [pub]
+ vid vndbid NOT NULL, -- [pub]
quote varchar(250) NOT NULL, -- [pub]
PRIMARY KEY(vid, quote)
);
-- releases
CREATE TABLE releases ( -- dbentry_type=r
- id SERIAL PRIMARY KEY, -- [pub]
+ id vndbid NOT NULL PRIMARY KEY DEFAULT vndbid('r', nextval('releases_id_seq')::int) CONSTRAINT releases_id_check CHECK(vndbid_type(id) = 'r'), -- [pub]
type release_type NOT NULL DEFAULT 'complete', -- [pub]
gtin bigint NOT NULL DEFAULT 0, -- [pub]
l_toranoana bigint NOT NULL DEFAULT 0, -- [pub]
@@ -433,7 +438,7 @@ CREATE TABLE releases_hist (
-- releases_lang
CREATE TABLE releases_lang (
- id integer NOT NULL, -- [pub]
+ id vndbid NOT NULL, -- [pub]
lang language NOT NULL, -- [pub]
PRIMARY KEY(id, lang)
);
@@ -447,7 +452,7 @@ CREATE TABLE releases_lang_hist (
-- releases_media
CREATE TABLE releases_media (
- id integer NOT NULL, -- [pub]
+ id vndbid NOT NULL, -- [pub]
medium medium NOT NULL, -- [pub]
qty smallint NOT NULL DEFAULT 1, -- [pub]
PRIMARY KEY(id, medium, qty)
@@ -463,7 +468,7 @@ CREATE TABLE releases_media_hist (
-- releases_platforms
CREATE TABLE releases_platforms (
- id integer NOT NULL, -- [pub]
+ id vndbid NOT NULL, -- [pub]
platform platform NOT NULL, -- [pub]
PRIMARY KEY(id, platform)
);
@@ -477,8 +482,8 @@ CREATE TABLE releases_platforms_hist (
-- releases_producers
CREATE TABLE releases_producers (
- id integer NOT NULL, -- [pub]
- pid integer NOT NULL, -- [pub] producers.id
+ id vndbid NOT NULL, -- [pub]
+ pid vndbid NOT NULL, -- [pub] producers.id
developer boolean NOT NULL DEFAULT FALSE, -- [pub]
publisher boolean NOT NULL DEFAULT TRUE, -- [pub]
CONSTRAINT releases_producers_check1 CHECK(developer OR publisher),
@@ -488,7 +493,7 @@ CREATE TABLE releases_producers (
-- releases_producers_hist
CREATE TABLE releases_producers_hist (
chid integer NOT NULL,
- pid integer NOT NULL, -- producers.id
+ pid vndbid NOT NULL, -- producers.id
developer boolean NOT NULL DEFAULT FALSE,
publisher boolean NOT NULL DEFAULT TRUE,
CHECK(developer OR publisher),
@@ -497,22 +502,22 @@ CREATE TABLE releases_producers_hist (
-- releases_vn
CREATE TABLE releases_vn (
- id integer NOT NULL, -- [pub]
- vid integer NOT NULL, -- [pub] vn.id
+ id vndbid NOT NULL, -- [pub]
+ vid vndbid NOT NULL, -- [pub] vn.id
PRIMARY KEY(id, vid)
);
-- releases_vn_hist
CREATE TABLE releases_vn_hist (
chid integer NOT NULL,
- vid integer NOT NULL, -- vn.id
+ vid vndbid NOT NULL, -- vn.id
PRIMARY KEY(chid, vid)
);
-- reports
CREATE TABLE reports (
id SERIAL PRIMARY KEY,
- uid integer, -- user who created the report, if logged in
+ uid vndbid, -- user who created the report, if logged in
date timestamptz NOT NULL DEFAULT NOW(),
lastmod timestamptz,
status report_status NOT NULL DEFAULT 'new',
@@ -527,9 +532,9 @@ CREATE TABLE reports (
-- reviews
CREATE TABLE reviews (
id vndbid PRIMARY KEY DEFAULT vndbid('w', nextval('reviews_seq')::int) CONSTRAINT reviews_id_check CHECK(vndbid_type(id) = 'w'),
- vid integer NOT NULL,
- uid integer,
- rid integer,
+ vid vndbid NOT NULL,
+ uid vndbid,
+ rid vndbid,
date timestamptz NOT NULL DEFAULT NOW(),
lastmod timestamptz,
c_up integer NOT NULL DEFAULT 0,
@@ -546,7 +551,7 @@ CREATE TABLE reviews (
-- reviews_posts
CREATE TABLE reviews_posts (
id vndbid NOT NULL,
- uid integer,
+ uid vndbid,
date timestamptz NOT NULL DEFAULT NOW(),
edited timestamptz,
num smallint NOT NULL,
@@ -558,7 +563,7 @@ CREATE TABLE reviews_posts (
-- reviews_votes
CREATE TABLE reviews_votes (
id vndbid NOT NULL,
- uid int,
+ uid vndbid,
date timestamptz NOT NULL,
vote boolean NOT NULL, -- true = upvote, false = downvote
overrule boolean NOT NULL DEFAULT false,
@@ -567,8 +572,8 @@ CREATE TABLE reviews_votes (
-- rlists
CREATE TABLE rlists (
- uid integer NOT NULL DEFAULT 0, -- [pub]
- rid integer NOT NULL DEFAULT 0, -- [pub]
+ uid vndbid NOT NULL, -- [pub]
+ rid vndbid NOT NULL, -- [pub]
added timestamptz NOT NULL DEFAULT NOW(), -- [pub]
status smallint NOT NULL DEFAULT 0, -- [pub]
PRIMARY KEY(uid, rid)
@@ -576,7 +581,7 @@ CREATE TABLE rlists (
-- saved_queries
CREATE TABLE saved_queries (
- uid integer NOT NULL,
+ uid vndbid NOT NULL,
qtype dbentry_type NOT NULL,
name text NOT NULL, -- Empty string is the users' default filter for the given qtype
query text NOT NULL, -- compact encoded form
@@ -585,7 +590,7 @@ CREATE TABLE saved_queries (
-- sessions
CREATE TABLE sessions (
- uid integer NOT NULL,
+ uid vndbid NOT NULL,
type session_type NOT NULL,
added timestamptz NOT NULL DEFAULT NOW(),
expires timestamptz NOT NULL,
@@ -647,7 +652,7 @@ CREATE TABLE shop_playasia_gtin (
-- staff
CREATE TABLE staff ( -- dbentry_type=s
- id SERIAL PRIMARY KEY, -- [pub]
+ id vndbid NOT NULL PRIMARY KEY DEFAULT vndbid('s', nextval('staff_id_seq')::int) CONSTRAINT staff_id_check CHECK(vndbid_type(id) = 's'), -- [pub]
gender gender NOT NULL DEFAULT 'unknown', -- [pub]
lang language NOT NULL DEFAULT 'ja', -- [pub]
aid integer NOT NULL DEFAULT 0, -- [pub] staff_alias.aid
@@ -679,7 +684,7 @@ CREATE TABLE staff_hist (
-- staff_alias
CREATE TABLE staff_alias (
- id integer NOT NULL, -- [pub]
+ id vndbid NOT NULL, -- [pub]
aid SERIAL PRIMARY KEY, -- [pub] Globally unique ID of this alias
name varchar(200) NOT NULL DEFAULT '', -- [pub]
original varchar(200) NOT NULL DEFAULT '' -- [pub]
@@ -705,7 +710,7 @@ CREATE TABLE tags (
id SERIAL NOT NULL PRIMARY KEY, -- [pub]
cat tag_category NOT NULL DEFAULT 'cont', -- [pub]
added timestamptz NOT NULL DEFAULT NOW(),
- addedby integer,
+ addedby vndbid,
c_items integer NOT NULL DEFAULT 0,
state smallint NOT NULL DEFAULT 0, -- [pub]
defaultspoil smallint NOT NULL DEFAULT 0, -- [pub]
@@ -731,8 +736,8 @@ CREATE TABLE tags_parents (
-- tags_vn
CREATE TABLE tags_vn (
tag integer NOT NULL, -- [pub]
- vid integer NOT NULL, -- [pub]
- uid integer, -- [pub]
+ vid vndbid NOT NULL, -- [pub]
+ uid vndbid, -- [pub]
vote smallint NOT NULL DEFAULT 3 CHECK (vote >= -3 AND vote <= 3 AND vote <> 0), -- [pub]
spoiler smallint CHECK(spoiler >= 0 AND spoiler <= 2), -- [pub]
date timestamptz NOT NULL DEFAULT NOW(), -- [pub]
@@ -743,7 +748,7 @@ CREATE TABLE tags_vn (
-- tags_vn_inherit
CREATE TABLE tags_vn_inherit (
tag integer NOT NULL,
- vid integer NOT NULL,
+ vid vndbid NOT NULL,
rating real NOT NULL,
spoiler smallint NOT NULL
);
@@ -770,7 +775,7 @@ CREATE TABLE threads_poll_options (
-- threads_poll_votes
CREATE TABLE threads_poll_votes (
- uid integer NOT NULL,
+ uid vndbid NOT NULL,
optid integer NOT NULL,
date timestamptz DEFAULT NOW(),
PRIMARY KEY (optid, uid)
@@ -779,7 +784,7 @@ CREATE TABLE threads_poll_votes (
-- threads_posts
CREATE TABLE threads_posts (
tid vndbid NOT NULL,
- uid integer,
+ uid vndbid,
date timestamptz NOT NULL DEFAULT NOW(),
edited timestamptz,
num smallint NOT NULL,
@@ -793,8 +798,7 @@ CREATE TABLE threads_posts (
CREATE TABLE threads_boards (
tid vndbid NOT NULL,
type board_type NOT NULL,
- iid integer NOT NULL DEFAULT 0,
- PRIMARY KEY(tid, type, iid)
+ iid vndbid
);
-- trace_log
@@ -818,7 +822,7 @@ CREATE TABLE traits (
id SERIAL PRIMARY KEY, -- [pub]
"group" integer, -- [pub]
added timestamptz NOT NULL DEFAULT NOW(),
- addedby integer,
+ addedby vndbid,
c_items integer NOT NULL DEFAULT 0,
state smallint NOT NULL DEFAULT 0, -- [pub]
"order" smallint NOT NULL DEFAULT 0, -- [pub]
@@ -836,7 +840,7 @@ CREATE TABLE traits (
-- into parent traits. In order to improve performance, there are no foreign
-- key constraints on this table.
CREATE TABLE traits_chars (
- cid integer NOT NULL, -- chars (id)
+ cid vndbid NOT NULL, -- chars (id)
tid integer NOT NULL, -- traits (id)
spoil smallint NOT NULL DEFAULT 0
);
@@ -850,7 +854,7 @@ CREATE TABLE traits_parents (
-- ulist_labels
CREATE TABLE ulist_labels (
- uid integer NOT NULL, -- [pub] user.id
+ uid vndbid NOT NULL, -- [pub] user.id
id integer NOT NULL, -- [pub] 0 < builtin < 10 <= custom, ids are reused
private boolean NOT NULL,
label text NOT NULL, -- [pub]
@@ -859,8 +863,8 @@ CREATE TABLE ulist_labels (
-- ulist_vns
CREATE TABLE ulist_vns (
- uid integer NOT NULL, -- [pub] users.id
- vid integer NOT NULL, -- [pub] vn.id
+ uid vndbid NOT NULL, -- [pub] users.id
+ vid vndbid NOT NULL, -- [pub] vn.id
added timestamptz NOT NULL DEFAULT NOW(), -- [pub]
lastmod timestamptz NOT NULL DEFAULT NOW(), -- [pub] updated when anything in this row has changed?
vote_date timestamptz, -- [pub] Used for "recent votes" - also updated when vote has changed?
@@ -873,9 +877,9 @@ CREATE TABLE ulist_vns (
-- ulist_vns_labels
CREATE TABLE ulist_vns_labels (
- uid integer NOT NULL, -- [pub] user.id
+ uid vndbid NOT NULL, -- [pub] user.id
lbl integer NOT NULL, -- [pub]
- vid integer NOT NULL, -- [pub] vn.id
+ vid vndbid NOT NULL, -- [pub] vn.id
PRIMARY KEY(uid, lbl, vid)
);
@@ -883,7 +887,7 @@ CREATE TABLE ulist_vns_labels (
CREATE TABLE users (
registered timestamptz NOT NULL DEFAULT NOW(),
last_reports timestamptz, -- For mods: Most recent activity seen on the reports listing
- id SERIAL NOT NULL PRIMARY KEY, -- [pub]
+ id vndbid NOT NULL PRIMARY KEY DEFAULT vndbid('u', nextval('users_id_seq')::int) CONSTRAINT users_id_check CHECK(vndbid_type(id) = 'u'), -- [pub]
c_votes integer NOT NULL DEFAULT 0,
c_changes integer NOT NULL DEFAULT 0,
c_tags integer NOT NULL DEFAULT 0,
@@ -944,7 +948,7 @@ CREATE TABLE users (
-- vn
CREATE TABLE vn ( -- dbentry_type=v
- id SERIAL PRIMARY KEY, -- [pub]
+ id vndbid NOT NULL PRIMARY KEY DEFAULT vndbid('v', nextval('vn_id_seq')::int) CONSTRAINT vn_id_check CHECK(vndbid_type(id) = 'v'), -- [pub]
olang language NOT NULL DEFAULT 'ja', -- [pub]
image vndbid CONSTRAINT vn_image_check CHECK(vndbid_type(image) = 'cv'), -- [pub]
l_wikidata integer, -- [pub]
@@ -989,7 +993,7 @@ CREATE TABLE vn_hist (
-- vn_anime
CREATE TABLE vn_anime (
- id integer NOT NULL, -- [pub]
+ id vndbid NOT NULL, -- [pub]
aid integer NOT NULL, -- [pub] anime.id
PRIMARY KEY(id, aid)
);
@@ -1003,8 +1007,8 @@ CREATE TABLE vn_anime_hist (
-- vn_relations
CREATE TABLE vn_relations (
- id integer NOT NULL, -- [pub]
- vid integer NOT NULL, -- [pub] vn.id
+ id vndbid NOT NULL, -- [pub]
+ vid vndbid NOT NULL, -- [pub] vn.id
relation vn_relation NOT NULL, -- [pub]
official boolean NOT NULL DEFAULT TRUE, -- [pub]
PRIMARY KEY(id, vid)
@@ -1013,7 +1017,7 @@ CREATE TABLE vn_relations (
-- vn_relations_hist
CREATE TABLE vn_relations_hist (
chid integer NOT NULL,
- vid integer NOT NULL, -- vn.id
+ vid vndbid NOT NULL, -- vn.id
relation vn_relation NOT NULL,
official boolean NOT NULL DEFAULT TRUE,
PRIMARY KEY(chid, vid)
@@ -1021,9 +1025,9 @@ CREATE TABLE vn_relations_hist (
-- vn_screenshots
CREATE TABLE vn_screenshots (
- id integer NOT NULL, -- [pub]
+ id vndbid NOT NULL, -- [pub]
scr vndbid NOT NULL CONSTRAINT vn_screenshots_scr_check CHECK(vndbid_type(scr) = 'sf'), -- [pub] images.id
- rid integer, -- [pub] releases.id (only NULL for old revisions, nowadays not allowed anymore)
+ rid vndbid, -- [pub] releases.id (only NULL for old revisions, nowadays not allowed anymore)
nsfw boolean NOT NULL DEFAULT FALSE, -- (deprecated)
PRIMARY KEY(id, scr)
);
@@ -1032,16 +1036,16 @@ CREATE TABLE vn_screenshots (
CREATE TABLE vn_screenshots_hist (
chid integer NOT NULL,
scr vndbid NOT NULL CONSTRAINT vn_screenshots_hist_scr_check CHECK(vndbid_type(scr) = 'sf'),
- rid integer,
+ rid vndbid,
nsfw boolean NOT NULL DEFAULT FALSE,
PRIMARY KEY(chid, scr)
);
-- vn_seiyuu
CREATE TABLE vn_seiyuu (
- id integer NOT NULL, -- [pub]
+ id vndbid NOT NULL, -- [pub]
aid integer NOT NULL, -- [pub] staff_alias.aid
- cid integer NOT NULL, -- [pub] chars.id
+ cid vndbid NOT NULL, -- [pub] chars.id
note varchar(250) NOT NULL DEFAULT '', -- [pub]
PRIMARY KEY (id, aid, cid)
);
@@ -1050,14 +1054,14 @@ CREATE TABLE vn_seiyuu (
CREATE TABLE vn_seiyuu_hist (
chid integer NOT NULL,
aid integer NOT NULL, -- staff_alias.aid, but can't reference it because the alias may have been deleted
- cid integer NOT NULL, -- chars.id
+ cid vndbid NOT NULL, -- chars.id
note varchar(250) NOT NULL DEFAULT '',
PRIMARY KEY (chid, aid, cid)
);
-- vn_staff
CREATE TABLE vn_staff (
- id integer NOT NULL, -- [pub]
+ id vndbid NOT NULL, -- [pub]
aid integer NOT NULL, -- [pub] staff_alias.aid
role credit_type NOT NULL DEFAULT 'staff', -- [pub]
note varchar(250) NOT NULL DEFAULT '', -- [pub]
diff --git a/sql/tableattrs.sql b/sql/tableattrs.sql
index a43e1c62..516c97e4 100644
--- a/sql/tableattrs.sql
+++ b/sql/tableattrs.sql
@@ -133,6 +133,7 @@ CREATE UNIQUE INDEX reviews_votes_id_uid ON reviews_votes (id,uid);
CREATE UNIQUE INDEX reviews_votes_id_ip ON reviews_votes (id,ip);
CREATE INDEX staff_alias_id ON staff_alias (id);
CREATE UNIQUE INDEX tags_vn_pkey ON tags_vn (tag,vid,uid);
+CREATE UNIQUE INDEX threads_boards_pkey ON threads_boards (tid,type,COALESCE(iid, 'r1')); -- 'r1' is an invalid board id
CREATE INDEX tags_vn_date ON tags_vn (date);
CREATE INDEX tags_vn_inherit_tag_vid ON tags_vn_inherit (tag, vid);
CREATE INDEX tags_vn_uid ON tags_vn (uid) WHERE uid IS NOT NULL;
@@ -147,8 +148,8 @@ CREATE INDEX vn_screenshots_scr ON vn_screenshots (scr);
CREATE INDEX vn_seiyuu_aid ON vn_seiyuu (aid); -- Only used on /s+?
CREATE INDEX vn_seiyuu_cid ON vn_seiyuu (cid); -- Only used on /c+?
CREATE INDEX vn_staff_aid ON vn_staff (aid);
-CREATE UNIQUE INDEX changes_itemrev ON changes (type, itemid, rev);
-CREATE UNIQUE INDEX chars_vns_pkey ON chars_vns (id, vid, COALESCE(rid, 0));
-CREATE UNIQUE INDEX chars_vns_hist_pkey ON chars_vns_hist (chid, vid, COALESCE(rid, 0));
+CREATE UNIQUE INDEX changes_itemrev ON changes (itemid, rev);
+CREATE UNIQUE INDEX chars_vns_pkey ON chars_vns (id, vid, COALESCE(rid, 'v1')); -- 'v1' is an invalid release id, but works as a 'no release specified' value in the UNIQUE qualifier.
+CREATE UNIQUE INDEX chars_vns_hist_pkey ON chars_vns_hist (chid, vid, COALESCE(rid, 'v1'));
CREATE INDEX ulist_vns_voted ON ulist_vns (vid, vote_date) WHERE vote IS NOT NULL; -- For VN recent votes & vote graph. INCLUDE(vote) speeds up vote graph even more
CREATE INDEX users_ign_votes ON users (id) WHERE ign_votes;
diff --git a/util/dbdump.pl b/util/dbdump.pl
index 3a088804..1695d911 100755
--- a/util/dbdump.pl
+++ b/util/dbdump.pl
@@ -201,7 +201,7 @@ sub export_import_script {
my $schema = $schema->{$table->{name}};
print $F "\n";
print $F "CREATE TABLE \"$table->{name}\" (\n";
- print $F join ",\n", map " $_->{decl}" =~ s/" serial/" integer/ir =~ s/ +(?:check|constraint) +.*//ir, grep $_->{pub}, @{$schema->{cols}};
+ print $F join ",\n", map " $_->{decl}" =~ s/" serial/" integer/ir =~ s/ +(?:check|constraint|default) +.*//ir, grep $_->{pub}, @{$schema->{cols}};
print $F ",\n PRIMARY KEY(".join(', ', map "\"$_\"", @{$schema->{primary}}).")" if $schema->{primary};
print $F "\n);\n";
}
@@ -331,7 +331,7 @@ sub export_votes {
open my $F, '>:gzip:utf8', $dest;
$db->do(q{COPY (
- SELECT uv.vid||' '||uv.uid||' '||uv.vote||' '||to_char(uv.vote_date, 'YYYY-MM-DD')
+ SELECT vndbid_num(uv.vid)||' '||vndbid_num(uv.uid)||' '||uv.vote||' '||to_char(uv.vote_date, 'YYYY-MM-DD')
FROM ulist_vns uv
JOIN users u ON u.id = uv.uid
JOIN vn v ON v.id = uv.vid
diff --git a/util/devdump.pl b/util/devdump.pl
index fe126e57..58844dba 100755
--- a/util/devdump.pl
+++ b/util/devdump.pl
@@ -17,28 +17,29 @@ use lib $ROOT.'/lib';
my $db = DBI->connect('dbi:Pg:dbname=vndb', 'vndb', undef, { RaiseError => 1 });
+sub ids { join ',', map "'$_'", @_ }
# Figure out which DB entries to export
-my @vids = (3, 17, 97, 183, 264, 266, 384, 407, 1910, 2932, 5922, 6438, 9837);
-my $vids = join ',', @vids;
+my @vids = (qw/v3 v17 v97 v183 v264 v266 v384 v407 v1910 v2932 v5922 v6438 v9837/);
+my $vids = ids @vids;
my $staff = $db->selectcol_arrayref(
"SELECT c2.itemid FROM vn_staff_hist v JOIN changes c ON c.id = v.chid JOIN staff_alias_hist a ON a.aid = v.aid JOIN changes c2 ON c2.id = a.chid WHERE c.itemid IN($vids) "
."UNION "
."SELECT c2.itemid FROM vn_seiyuu_hist v JOIN changes c ON c.id = v.chid JOIN staff_alias_hist a ON a.aid = v.aid JOIN changes c2 ON c2.id = a.chid WHERE c.itemid IN($vids)"
);
my $releases = $db->selectcol_arrayref("SELECT DISTINCT c.itemid FROM releases_vn_hist v JOIN changes c ON c.id = v.chid WHERE v.vid IN($vids)");
-my $producers = $db->selectcol_arrayref("SELECT pid FROM releases_producers_hist p JOIN changes c ON c.id = p.chid WHERE c.type = 'r' AND c.itemid IN(".join(',',@$releases).")");
+my $producers = $db->selectcol_arrayref("SELECT pid FROM releases_producers_hist p JOIN changes c ON c.id = p.chid WHERE c.itemid IN(".ids(@$releases).")");
my $characters = $db->selectcol_arrayref(
"SELECT DISTINCT c.itemid FROM chars_vns_hist e JOIN changes c ON c.id = e.chid WHERE e.vid IN($vids) "
."UNION "
."SELECT DISTINCT h.main FROM chars_vns_hist e JOIN changes c ON c.id = e.chid JOIN chars_hist h ON h.chid = e.chid WHERE e.vid IN($vids) AND h.main IS NOT NULL"
);
my $images = $db->selectcol_arrayref(q{
- SELECT image FROM chars_hist ch JOIN changes c ON c.id = ch.chid WHERE c.type = 'c' AND c.itemid IN(}.join(',',@$characters).qq{) AND ch.image IS NOT NULL
- UNION SELECT image FROM vn_hist vh JOIN changes c ON c.id = vh.chid WHERE c.type = 'v' AND c.itemid IN($vids) AND vh.image IS NOT NULL
- UNION SELECT scr FROM vn_screenshots_hist vs JOIN changes c ON c.id = vs.chid WHERE c.type = 'v' AND c.itemid IN($vids)
+ SELECT image FROM chars_hist ch JOIN changes c ON c.id = ch.chid WHERE c.itemid IN(}.ids(@$characters).qq{) AND ch.image IS NOT NULL
+ UNION SELECT image FROM vn_hist vh JOIN changes c ON c.id = vh.chid WHERE c.itemid IN($vids) AND vh.image IS NOT NULL
+ UNION SELECT scr FROM vn_screenshots_hist vs JOIN changes c ON c.id = vs.chid WHERE c.itemid IN($vids)
});
@@ -47,6 +48,7 @@ my $images = $db->selectcol_arrayref(q{
sub copy {
my($dest, $sql, $specials) = @_;
+ warn $dest;
$sql ||= "SELECT * FROM $dest";
$specials ||= {};
@@ -61,7 +63,7 @@ sub copy {
$sql = "SELECT " . join(',', map {
my $s = $specials->{$_} || '';
if($s eq 'user') {
- qq{CASE WHEN "$_" % 10 = 0 THEN NULL ELSE "$_" % 10 END AS "$_"}
+ qq{CASE WHEN vndbid_num("$_") % 10 = 0 THEN NULL ELSE vndbid('u', vndbid_num("$_") % 10) END AS "$_"}
} else {
qq{"$_"}
}
@@ -77,14 +79,14 @@ sub copy {
# Helper function to copy a full DB entry with history and all (doesn't handle references)
sub copy_entry {
- my($type, $tables, $ids) = @_;
- $ids = join ',', @$ids;
- copy changes => "SELECT * FROM changes WHERE type = '$type' AND itemid IN($ids)", {requester => 'user', ip => 'del'};
+ my($tables, $ids) = @_;
+ $ids = ids @$ids;
+ copy changes => "SELECT * FROM changes WHERE itemid IN($ids)", {requester => 'user', ip => 'del'};
for(@$tables) {
my $add = '';
$add = " AND vid IN($vids)" if /^releases_vn/ || /^vn_relations/ || /^chars_vns/;
copy $_ => "SELECT * FROM $_ WHERE id IN($ids) $add";
- copy "${_}_hist" => "SELECT x.* FROM ${_}_hist x JOIN changes c ON c.id = x.chid WHERE c.type = '$type' AND c.itemid IN($ids) $add";
+ copy "${_}_hist" => "SELECT x.* FROM ${_}_hist x JOIN changes c ON c.id = x.chid WHERE c.itemid IN($ids) $add";
}
}
@@ -109,15 +111,15 @@ sub copy_entry {
# A few pre-defined users
# This password is 'hunter2' with the default salt
my $pass = '000100000801ec4185fed438752d6b3b968e2b2cd045f70005cb7e10cafdbb694a82246bd34a065b6e977e0c3dcc';
- printf "INSERT INTO users (id, username, mail, perm_usermod, passwd, email_confirmed) VALUES (%d, '%s', '%s', %s, decode('%s', 'hex'), true);\n", @$_, $pass for(
- [ 2, 'admin', 'admin@vndb.org', 'true' ],
- [ 3, 'user1', 'user1@vndb.org', 'false'],
- [ 4, 'user2', 'user2@vndb.org', 'false'],
- [ 5, 'user3', 'user3@vndb.org', 'false'],
- [ 6, 'user4', 'user4@vndb.org', 'false'],
- [ 7, 'user5', 'user5@vndb.org', 'false'],
- [ 8, 'user6', 'user6@vndb.org', 'false'],
- [ 9, 'user7', 'user7@vndb.org', 'false'],
+ printf "INSERT INTO users (id, username, mail, perm_usermod, passwd, email_confirmed) VALUES ('%s', '%s', '%s', %s, decode('%s', 'hex'), true);\n", @$_, $pass for(
+ [ 'u2', 'admin', 'admin@vndb.org', 'true' ],
+ [ 'u3', 'user1', 'user1@vndb.org', 'false'],
+ [ 'u4', 'user2', 'user2@vndb.org', 'false'],
+ [ 'u5', 'user3', 'user3@vndb.org', 'false'],
+ [ 'u6', 'user4', 'user4@vndb.org', 'false'],
+ [ 'u7', 'user5', 'user5@vndb.org', 'false'],
+ [ 'u8', 'user6', 'user6@vndb.org', 'false'],
+ [ 'u9', 'user7', 'user7@vndb.org', 'false'],
);
print "SELECT ulist_labels_create(id) FROM users;\n";
@@ -132,9 +134,9 @@ sub copy_entry {
copy 'wikidata';
# Image metadata
- my $image_ids = join ',', map "'$_'", @$images;
+ my $image_ids = ids @$images;
copy images => "SELECT * FROM images WHERE id IN($image_ids)";
- copy image_votes => "SELECT DISTINCT ON (id,uid%10) * FROM image_votes WHERE id IN($image_ids)", { uid => 'user' };
+ copy image_votes => "SELECT DISTINCT ON (id,vndbid('u', vndbid_num(uid)%10+10)) * FROM image_votes WHERE id IN($image_ids)", { uid => 'user' };
# Threads (announcements)
my $threads = join ',', map "'$_'", @{ $db->selectcol_arrayref("SELECT tid FROM threads_boards b WHERE b.type = 'an'") };
@@ -143,31 +145,31 @@ sub copy_entry {
copy threads_posts => "SELECT * FROM threads_posts WHERE tid IN($threads)", { uid => 'user' };
# Doc pages
- copy_entry d => ['docs'], $db->selectcol_arrayref('SELECT id FROM docs');
+ copy_entry ['docs'], $db->selectcol_arrayref('SELECT id FROM docs');
# Staff
- copy_entry s => [qw/staff staff_alias/], $staff;
+ copy_entry [qw/staff staff_alias/], $staff;
# Producers (TODO: Relations)
- copy_entry p => [qw/producers/], $producers;
+ copy_entry [qw/producers/], $producers;
# Characters
- copy_entry c => [qw/chars chars_traits chars_vns/], $characters;
+ copy_entry [qw/chars chars_traits chars_vns/], $characters;
# Visual novels
- copy anime => "SELECT DISTINCT a.* FROM anime a JOIN vn_anime_hist v ON v.aid = a.id JOIN changes c ON c.id = v.chid WHERE c.type = 'v' AND c.itemid IN($vids)";
- copy_entry v => [qw/vn vn_anime vn_seiyuu vn_staff vn_relations vn_screenshots/], \@vids;
+ copy anime => "SELECT DISTINCT a.* FROM anime a JOIN vn_anime_hist v ON v.aid = a.id JOIN changes c ON c.id = v.chid WHERE c.itemid IN($vids)";
+ copy_entry [qw/vn vn_anime vn_seiyuu vn_staff vn_relations vn_screenshots/], \@vids;
# VN-related niceties
- copy tags_vn => "SELECT DISTINCT ON (tag,vid,uid%10) * FROM tags_vn WHERE vid IN($vids)", {uid => 'user'};
+ copy tags_vn => "SELECT DISTINCT ON (tag,vid,vndbid_num(uid)%10) * FROM tags_vn WHERE vid IN($vids)", {uid => 'user'};
copy quotes => "SELECT * FROM quotes WHERE vid IN($vids)";
- my $votes = "SELECT vid, uid%8+2 AS uid, (percentile_cont((uid%8+1)::float/9) WITHIN GROUP (ORDER BY vote))::smallint AS vote, MIN(vote_date) AS vote_date"
- ." FROM ulist_vns WHERE vid IN($vids) AND vote IS NOT NULL GROUP BY vid, uid%8";
+ my $votes = "SELECT vid, vndbid('u', vndbid_num(uid)%8+2) AS uid, (percentile_cont((vndbid_num(uid)%8+1)::float/9) WITHIN GROUP (ORDER BY vote))::smallint AS vote, MIN(vote_date) AS vote_date"
+ ." FROM ulist_vns WHERE vid IN($vids) AND vote IS NOT NULL GROUP BY vid, vndbid_num(uid)%8";
copy ulist_vns => $votes, {uid => 'user'};
copy ulist_vns_labels => "SELECT vid, uid, 7 AS lbl FROM ($votes) x", {uid => 'user'};
# Releases
- copy_entry r => [qw/releases releases_lang releases_media releases_platforms releases_producers releases_vn/], $releases;
+ copy_entry [qw/releases releases_lang releases_media releases_platforms releases_producers releases_vn/], $releases;
print "\\i sql/tableattrs.sql\n";
print "\\i sql/triggers.sql\n";
diff --git a/util/revision-integrity.pl b/util/revision-integrity.pl
index 3c8a552d..8c542f92 100755
--- a/util/revision-integrity.pl
+++ b/util/revision-integrity.pl
@@ -34,6 +34,6 @@ for my $table (sort { $a->{name} cmp $b->{name} } values %$schema) {
EXCEPT
SELECT '$main', c.itemid, $histlock $cols
FROM $table->{name} e
- JOIN changes c ON c.type = '$schema->{$type}{dbentry_type}' AND e.chid = c.id
- WHERE NOT EXISTS(SELECT 1 FROM changes c2 WHERE c2.type = c.type AND c2.itemid = c.itemid AND c2.rev > c.rev);\n\n"
+ JOIN changes c ON e.chid = c.id
+ WHERE NOT EXISTS(SELECT 1 FROM changes c2 WHERE c2.itemid = c.itemid AND c2.rev > c.rev);\n\n"
}
diff --git a/util/saved-queries.pl b/util/saved-queries.pl
index 5c7b70ee..f93d4643 100755
--- a/util/saved-queries.pl
+++ b/util/saved-queries.pl
@@ -25,7 +25,7 @@ for my $r (tuwf->dbAlli('SELECT uid, qtype, name, query FROM saved_queries')->@*
my $q = eval { tuwf->compile({advsearch => $r->{qtype}})->validate($r->{query})->data };
if(!$q) {
$err++;
- warn "Invalid query: u$r->{uid}, $r->{qtype}, \"$r->{name}\": $r->{query}\n";
+ warn "Invalid query: $r->{uid}, $r->{qtype}, \"$r->{name}\": $r->{query}\n";
next;
}
@@ -33,7 +33,7 @@ for my $r (tuwf->dbAlli('SELECT uid, qtype, name, query FROM saved_queries')->@*
if($r->{qtype} eq 'v' && !$r->{name} && $q->{query}[0] eq 'and') {
my @lengths = grep ref $_ && $_->[0] eq 'length', $q->{query}->@*;
$q->{query} = [ grep(!ref $_ || $_->[0] ne 'length', $q->{query}->@*), [ 'or', @lengths ] ] if @lengths > 1;
- warn "Converted 'AND length' to 'OR length' for u$r->{uid}\n" if @lengths > 1;
+ warn "Converted 'AND length' to 'OR length' for $r->{uid}\n" if @lengths > 1;
}
# "Unlabeled && !Unlabeled" used to mean "on my list" and was what the old filter conversions used.
@@ -42,17 +42,17 @@ for my $r (tuwf->dbAlli('SELECT uid, qtype, name, query FROM saved_queries')->@*
my sub isonlist {
my $q = $_;
ref $q && $q->[0] eq 'or' && @$q == 3
- && $q->[1][0] eq 'label' && $q->[1][1] eq '=' && ref $q->[1][2] && $q->[1][2][0] eq "u$r->{uid}" && $q->[1][2][1] eq 0
- && $q->[2][0] eq 'label' && $q->[2][1] eq '!=' && ref $q->[2][2] && $q->[2][2][0] eq "u$r->{uid}" && $q->[2][2][1] eq 0
+ && $q->[1][0] eq 'label' && $q->[1][1] eq '=' && ref $q->[1][2] && $q->[1][2][0] eq $r->{uid} && $q->[1][2][1] eq 0
+ && $q->[2][0] eq 'label' && $q->[2][1] eq '!=' && ref $q->[2][2] && $q->[2][2][0] eq $r->{uid} && $q->[2][2][1] eq 0
}
my $e=0;
$q->{query} = [ map isonlist($_) ? do { $e=1; [ 'on-list', '=', 1 ] } : $_, $q->{query}->@* ];
- warn "Converted Unlabaled hack to on-list for u$r->{uid}\n" if $e;
+ warn "Converted Unlabaled hack to on-list for $r->{uid}\n" if $e;
}
my $qs = $q->query_encode;
if(!$qs) {
- warn "Empty query: u$r->{uid}, $r->{qtype}, \"$r->{name}\": $r->{query}\n";
+ warn "Empty query: $r->{uid}, $r->{qtype}, \"$r->{name}\": $r->{query}\n";
next;
}
if($qs ne $r->{query}) {
diff --git a/util/sqleditfunc.pl b/util/sqleditfunc.pl
index 2af28b6a..67aef6cf 100755
--- a/util/sqleditfunc.pl
+++ b/util/sqleditfunc.pl
@@ -37,15 +37,15 @@ sub gensql {
$_, join ', ', @{$ts{$_}}), sort keys %ts;
$replace{copyfromtemp} = join "\n", map sprintf(
- " DELETE FROM %1\$s WHERE id = r.itemid;\n".
- " INSERT INTO %1\$s (id, %2\$s) SELECT r.itemid, %2\$s FROM edit_%1\$s;\n".
- " INSERT INTO %1\$s_hist (chid, %2\$s) SELECT r.chid, %2\$s FROM edit_%1\$s;",
+ " DELETE FROM %1\$s WHERE id = nitemid;\n".
+ " INSERT INTO %1\$s (id, %2\$s) SELECT nitemid, %2\$s FROM edit_%1\$s;\n".
+ " INSERT INTO %1\$s_hist (chid, %2\$s) SELECT nchid, %2\$s FROM edit_%1\$s;",
$_, join ', ', @{$ts{$_}}), grep $_ ne $item, sort keys %ts;
$replace{copymainfromtemp} = sprintf
- " INSERT INTO %1\$s_hist (chid, %2\$s) SELECT r.chid, %2\$s FROM edit_%1\$s;\n".
+ " INSERT INTO %1\$s_hist (chid, %2\$s) SELECT nchid, %2\$s FROM edit_%1\$s;\n".
" UPDATE %1\$s SET locked = (SELECT ilock FROM edit_revision), hidden = (SELECT ihid FROM edit_revision),\n".
- " %3\$s FROM edit_%1\$s x WHERE id = r.itemid;",
+ " %3\$s FROM edit_%1\$s x WHERE id = nitemid;",
$item, join(', ', @{$ts{$item}}), join(', ', map "$_ = x.$_", @{$ts{$item}});
$template =~ s/{([a-z]+)}/$replace{$1}/gr;
@@ -59,7 +59,7 @@ print $F gensql $_ for sort grep $schema->{$_}{dbentry_type}, keys %$schema;
__DATA__
-CREATE OR REPLACE FUNCTION edit_{itemtype}_init(xid integer, xrev integer) RETURNS void AS $$
+CREATE OR REPLACE FUNCTION edit_{itemtype}_init(xid vndbid, xrev integer) RETURNS void AS $$
DECLARE
xchid integer;
BEGIN
@@ -70,7 +70,7 @@ BEGIN
TRUNCATE {temptablenames};
END;
-- Create edit_revision table and get relevant change ID.
- SELECT edit_revtable('{itemtype}', xid, xrev) INTO xchid;
+ SELECT edit_revtable(xid, xrev) INTO xchid;
-- new entry, load defaults
IF xchid IS NULL THEN
INSERT INTO edit_{item} DEFAULT VALUES;
@@ -82,18 +82,26 @@ END;
$$ LANGUAGE plpgsql;
-CREATE OR REPLACE FUNCTION edit_{itemtype}_commit() RETURNS edit_rettype AS $$
-DECLARE
- r edit_rettype;
+CREATE OR REPLACE FUNCTION edit_{itemtype}_commit(out nchid integer, out nitemid vndbid, out nrev integer) AS $$
BEGIN
IF (SELECT COUNT(*) FROM edit_{item}) <> 1 THEN
RAISE 'edit_{item} must have exactly one row!';
END IF;
- SELECT INTO r * FROM edit_commit();
+ SELECT itemid INTO nitemid FROM edit_revision;
+ -- figure out revision number
+ SELECT MAX(rev)+1 INTO nrev FROM changes WHERE itemid = nitemid;
+ SELECT COALESCE(nrev, 1) INTO nrev;
+ -- insert DB item
+ IF nitemid IS NULL THEN
+ INSERT INTO {item} DEFAULT VALUES RETURNING id INTO nitemid;
+ END IF;
+ -- insert change
+ INSERT INTO changes (itemid, rev, requester, ip, comments, ihid, ilock)
+ SELECT nitemid, nrev, requester, ip, comments, ihid, ilock FROM edit_revision RETURNING id INTO nchid;
+ -- insert data
{copyfromtemp}
{copymainfromtemp}
- PERFORM edit_committed('{itemtype}', r);
- RETURN r;
+ PERFORM edit_committed(nchid, nitemid, nrev);
END;
$$ LANGUAGE plpgsql;
diff --git a/util/updates/2021-03-01-entries-to-vndbid.sql b/util/updates/2021-03-01-entries-to-vndbid.sql
new file mode 100644
index 00000000..29669bea
--- /dev/null
+++ b/util/updates/2021-03-01-entries-to-vndbid.sql
@@ -0,0 +1,245 @@
+-- Public dump breakage:
+-- SELECT .. FROM vn WHERE id = 10;
+-- SELECT .. FROM vn WHERE id IN(1,2,3);
+-- SELECT 'https://vndb.org/v'||id FROM vn;
+
+BEGIN;
+
+ALTER TABLE changes DROP CONSTRAINT changes_requester_fkey;
+ALTER TABLE chars DROP CONSTRAINT chars_main_fkey;
+ALTER TABLE chars_hist DROP CONSTRAINT chars_hist_main_fkey;
+ALTER TABLE chars_traits DROP CONSTRAINT chars_traits_id_fkey;
+ALTER TABLE chars_vns DROP CONSTRAINT chars_vns_id_fkey;
+ALTER TABLE chars_vns DROP CONSTRAINT chars_vns_rid_fkey;
+ALTER TABLE chars_vns DROP CONSTRAINT chars_vns_vid_fkey;
+ALTER TABLE chars_vns_hist DROP CONSTRAINT chars_vns_hist_rid_fkey;
+ALTER TABLE chars_vns_hist DROP CONSTRAINT chars_vns_hist_vid_fkey;
+ALTER TABLE image_votes DROP CONSTRAINT image_votes_uid_fkey;
+ALTER TABLE notification_subs DROP CONSTRAINT notification_subs_uid_fkey;
+ALTER TABLE notifications DROP CONSTRAINT notifications_uid_fkey;
+ALTER TABLE producers_relations DROP CONSTRAINT producers_relations_pid_fkey;
+ALTER TABLE producers_relations_hist DROP CONSTRAINT producers_relations_hist_pid_fkey;
+ALTER TABLE quotes DROP CONSTRAINT quotes_vid_fkey;
+ALTER TABLE releases_lang DROP CONSTRAINT releases_lang_id_fkey;
+ALTER TABLE releases_media DROP CONSTRAINT releases_media_id_fkey;
+ALTER TABLE releases_platforms DROP CONSTRAINT releases_platforms_id_fkey;
+ALTER TABLE releases_producers DROP CONSTRAINT releases_producers_id_fkey;
+ALTER TABLE releases_producers DROP CONSTRAINT releases_producers_pid_fkey;
+ALTER TABLE releases_producers_hist DROP CONSTRAINT releases_producers_hist_pid_fkey;
+ALTER TABLE releases_vn DROP CONSTRAINT releases_vn_id_fkey;
+ALTER TABLE releases_vn DROP CONSTRAINT releases_vn_vid_fkey;
+ALTER TABLE releases_vn_hist DROP CONSTRAINT releases_vn_hist_vid_fkey;
+ALTER TABLE reviews DROP CONSTRAINT reviews_rid_fkey;
+ALTER TABLE reviews DROP CONSTRAINT reviews_uid_fkey;
+ALTER TABLE reviews DROP CONSTRAINT reviews_vid_fkey;
+ALTER TABLE reviews_posts DROP CONSTRAINT reviews_posts_uid_fkey;
+ALTER TABLE reviews_votes DROP CONSTRAINT reviews_votes_uid_fkey;
+ALTER TABLE rlists DROP CONSTRAINT rlists_rid_fkey;
+ALTER TABLE rlists DROP CONSTRAINT rlists_uid_fkey;
+ALTER TABLE saved_queries DROP CONSTRAINT saved_queries_uid_fkey;
+ALTER TABLE sessions DROP CONSTRAINT sessions_uid_fkey;
+ALTER TABLE staff_alias DROP CONSTRAINT staff_alias_id_fkey;
+ALTER TABLE tags DROP CONSTRAINT tags_addedby_fkey;
+ALTER TABLE tags_vn DROP CONSTRAINT tags_vn_uid_fkey;
+ALTER TABLE tags_vn DROP CONSTRAINT tags_vn_vid_fkey;
+ALTER TABLE threads_poll_votes DROP CONSTRAINT threads_poll_votes_uid_fkey;
+ALTER TABLE threads_posts DROP CONSTRAINT threads_posts_uid_fkey;
+ALTER TABLE traits DROP CONSTRAINT traits_addedby_fkey;
+ALTER TABLE ulist_labels DROP CONSTRAINT ulist_labels_uid_fkey;
+ALTER TABLE ulist_vns DROP CONSTRAINT ulist_vns_uid_fkey;
+ALTER TABLE ulist_vns DROP CONSTRAINT ulist_vns_vid_fkey;
+ALTER TABLE ulist_vns_labels DROP CONSTRAINT ulist_vns_labels_uid_fkey;
+ALTER TABLE ulist_vns_labels DROP CONSTRAINT ulist_vns_labels_uid_lbl_fkey;
+ALTER TABLE ulist_vns_labels DROP CONSTRAINT ulist_vns_labels_uid_vid_fkey;
+ALTER TABLE ulist_vns_labels DROP CONSTRAINT ulist_vns_labels_vid_fkey;
+ALTER TABLE vn_anime DROP CONSTRAINT vn_anime_id_fkey;
+ALTER TABLE vn_relations DROP CONSTRAINT vn_relations_id_fkey;
+ALTER TABLE vn_relations DROP CONSTRAINT vn_relations_vid_fkey;
+ALTER TABLE vn_relations_hist DROP CONSTRAINT vn_relations_vid_fkey;
+ALTER TABLE vn_screenshots DROP CONSTRAINT vn_screenshots_id_fkey;
+ALTER TABLE vn_screenshots DROP CONSTRAINT vn_screenshots_rid_fkey;
+ALTER TABLE vn_screenshots_hist DROP CONSTRAINT vn_screenshots_hist_rid_fkey;
+ALTER TABLE vn_seiyuu DROP CONSTRAINT vn_seiyuu_cid_fkey;
+ALTER TABLE vn_seiyuu DROP CONSTRAINT vn_seiyuu_id_fkey;
+ALTER TABLE vn_seiyuu_hist DROP CONSTRAINT vn_seiyuu_hist_cid_fkey;
+ALTER TABLE vn_staff DROP CONSTRAINT vn_staff_id_fkey;
+
+DROP INDEX chars_vns_pkey;
+DROP INDEX chars_vns_hist_pkey;
+
+ALTER TABLE rlists ALTER COLUMN uid DROP DEFAULT;
+ALTER TABLE rlists ALTER COLUMN rid DROP DEFAULT;
+
+
+DROP INDEX changes_itemrev;
+ALTER TABLE changes ALTER COLUMN itemid TYPE vndbid USING vndbid(type::text, itemid);
+ALTER TABLE changes DROP COLUMN type;
+
+ALTER TABLE threads_boards DROP CONSTRAINT threads_boards_pkey;
+ALTER TABLE threads_boards ALTER COLUMN iid DROP DEFAULT;
+ALTER TABLE threads_boards ALTER COLUMN iid DROP NOT NULL;
+ALTER TABLE threads_boards ALTER COLUMN iid TYPE vndbid USING CASE WHEN iid = 0 THEN NULL ELSE vndbid(type::text, iid) END;
+
+ALTER TABLE audit_log ALTER COLUMN by_uid TYPE vndbid USING vndbid('u', by_uid);
+ALTER TABLE audit_log ALTER COLUMN affected_uid TYPE vndbid USING vndbid('u', affected_uid);
+ALTER TABLE reports ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+
+
+ALTER TABLE chars ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE chars ALTER COLUMN id TYPE vndbid USING vndbid('c', id);
+ALTER TABLE chars ALTER COLUMN id SET DEFAULT vndbid('c', nextval('chars_id_seq')::int);
+ALTER TABLE chars ADD CONSTRAINT chars_id_check CHECK(vndbid_type(id) = 'c');
+
+ALTER TABLE chars ALTER COLUMN main TYPE vndbid USING vndbid('c', main);
+ALTER TABLE chars_hist ALTER COLUMN main TYPE vndbid USING vndbid('c', main);
+ALTER TABLE chars_traits ALTER COLUMN id TYPE vndbid USING vndbid('c', id);
+ALTER TABLE chars_vns ALTER COLUMN id TYPE vndbid USING vndbid('c', id);
+ALTER TABLE traits_chars ALTER COLUMN cid TYPE vndbid USING vndbid('c', cid);
+ALTER TABLE vn_seiyuu ALTER COLUMN cid TYPE vndbid USING vndbid('c', cid);
+ALTER TABLE vn_seiyuu_hist ALTER COLUMN cid TYPE vndbid USING vndbid('c', cid);
+
+
+ALTER TABLE docs ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE docs ALTER COLUMN id TYPE vndbid USING vndbid('d', id);
+ALTER TABLE docs ALTER COLUMN id SET DEFAULT vndbid('d', nextval('docs_id_seq')::int);
+ALTER TABLE docs ADD CONSTRAINT docs_id_check CHECK(vndbid_type(id) = 'd');
+
+
+ALTER TABLE producers ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE producers ALTER COLUMN id TYPE vndbid USING vndbid('p', id);
+ALTER TABLE producers ALTER COLUMN id SET DEFAULT vndbid('p', nextval('producers_id_seq')::int);
+ALTER TABLE producers ADD CONSTRAINT producers_id_check CHECK(vndbid_type(id) = 'p');
+
+ALTER TABLE producers_relations ALTER COLUMN id TYPE vndbid USING vndbid('p', id);
+ALTER TABLE producers_relations ALTER COLUMN pid TYPE vndbid USING vndbid('p', pid);
+ALTER TABLE producers_relations_hist ALTER COLUMN pid TYPE vndbid USING vndbid('p', pid);
+ALTER TABLE releases_producers ALTER COLUMN pid TYPE vndbid USING vndbid('p', pid);
+ALTER TABLE releases_producers_hist ALTER COLUMN pid TYPE vndbid USING vndbid('p', pid);
+
+
+ALTER TABLE releases ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE releases ALTER COLUMN id TYPE vndbid USING vndbid('r', id);
+ALTER TABLE releases ALTER COLUMN id SET DEFAULT vndbid('r', nextval('releases_id_seq')::int);
+ALTER TABLE releases ADD CONSTRAINT releases_id_check CHECK(vndbid_type(id) = 'r');
+
+ALTER TABLE chars_vns ALTER COLUMN rid TYPE vndbid USING vndbid('r', rid);
+ALTER TABLE chars_vns_hist ALTER COLUMN rid TYPE vndbid USING vndbid('r', rid);
+ALTER TABLE releases_lang ALTER COLUMN id TYPE vndbid USING vndbid('r', id);
+ALTER TABLE releases_media ALTER COLUMN id TYPE vndbid USING vndbid('r', id);
+ALTER TABLE releases_platforms ALTER COLUMN id TYPE vndbid USING vndbid('r', id);
+ALTER TABLE releases_producers ALTER COLUMN id TYPE vndbid USING vndbid('r', id);
+ALTER TABLE releases_vn ALTER COLUMN id TYPE vndbid USING vndbid('r', id);
+ALTER TABLE reviews ALTER COLUMN rid TYPE vndbid USING vndbid('r', rid);
+ALTER TABLE rlists ALTER COLUMN rid TYPE vndbid USING vndbid('r', rid);
+ALTER TABLE vn_screenshots ALTER COLUMN rid TYPE vndbid USING vndbid('r', rid);
+ALTER TABLE vn_screenshots_hist ALTER COLUMN rid TYPE vndbid USING vndbid('r', rid);
+
+
+ALTER TABLE staff ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE staff ALTER COLUMN id TYPE vndbid USING vndbid('s', id);
+ALTER TABLE staff ALTER COLUMN id SET DEFAULT vndbid('s', nextval('staff_id_seq')::int);
+ALTER TABLE staff ADD CONSTRAINT staff_id_check CHECK(vndbid_type(id) = 's');
+
+ALTER TABLE staff_alias ALTER COLUMN id TYPE vndbid USING vndbid('s', id);
+
+
+ALTER TABLE vn ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE vn ALTER COLUMN id TYPE vndbid USING vndbid('v', id);
+ALTER TABLE vn ALTER COLUMN id SET DEFAULT vndbid('v', nextval('vn_id_seq')::int);
+ALTER TABLE vn ADD CONSTRAINT vn_id_check CHECK(vndbid_type(id) = 'v');
+
+ALTER TABLE chars_vns ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE chars_vns_hist ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE quotes ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE releases_vn ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE releases_vn_hist ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE reviews ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE tags_vn ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE tags_vn_inherit ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE ulist_vns ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE ulist_vns_labels ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE vn_anime ALTER COLUMN id TYPE vndbid USING vndbid('v', id);
+ALTER TABLE vn_relations ALTER COLUMN id TYPE vndbid USING vndbid('v', id);
+ALTER TABLE vn_relations ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE vn_relations_hist ALTER COLUMN vid TYPE vndbid USING vndbid('v', vid);
+ALTER TABLE vn_screenshots ALTER COLUMN id TYPE vndbid USING vndbid('v', id);
+ALTER TABLE vn_seiyuu ALTER COLUMN id TYPE vndbid USING vndbid('v', id);
+ALTER TABLE vn_staff ALTER COLUMN id TYPE vndbid USING vndbid('v', id);
+
+
+ALTER TABLE users ALTER COLUMN id DROP DEFAULT;
+ALTER TABLE users ALTER COLUMN id TYPE vndbid USING vndbid('u', id);
+ALTER TABLE users ALTER COLUMN id SET DEFAULT vndbid('u', nextval('users_id_seq')::int);
+ALTER TABLE users ADD CONSTRAINT users_id_check CHECK(vndbid_type(id) = 'u');
+
+ALTER TABLE changes ALTER COLUMN requester TYPE vndbid USING vndbid('u', requester);
+ALTER TABLE image_votes ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE notification_subs ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE notifications ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE reviews ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE reviews_posts ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE reviews_votes ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE rlists ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE saved_queries ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE sessions ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE tags ALTER COLUMN addedby TYPE vndbid USING vndbid('u', addedby);
+ALTER TABLE tags_vn ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE threads_poll_votes ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE threads_posts ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE traits ALTER COLUMN addedby TYPE vndbid USING vndbid('u', addedby);
+ALTER TABLE ulist_labels ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE ulist_vns ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+ALTER TABLE ulist_vns_labels ALTER COLUMN uid TYPE vndbid USING vndbid('u', uid);
+
+ALTER TABLE images ALTER COLUMN c_uids DROP DEFAULT;
+ALTER TABLE images ALTER COLUMN c_uids TYPE vndbid[] USING '{}';
+ALTER TABLE images ALTER COLUMN c_uids SET DEFAULT '{}';
+
+DROP FUNCTION edit_revtable(dbentry_type, integer, integer);
+DROP FUNCTION edit_commit();
+DROP FUNCTION edit_committed(dbentry_type, edit_rettype);
+DROP FUNCTION edit_c_init(integer, integer);
+DROP FUNCTION edit_d_init(integer, integer);
+DROP FUNCTION edit_p_init(integer, integer);
+DROP FUNCTION edit_r_init(integer, integer);
+DROP FUNCTION edit_s_init(integer, integer);
+DROP FUNCTION edit_v_init(integer, integer);
+DROP FUNCTION edit_c_commit();
+DROP FUNCTION edit_d_commit();
+DROP FUNCTION edit_p_commit();
+DROP FUNCTION edit_r_commit();
+DROP FUNCTION edit_s_commit();
+DROP FUNCTION edit_v_commit();
+
+DROP FUNCTION update_vncache(integer);
+DROP FUNCTION tag_vn_calc(integer);
+DROP FUNCTION traits_chars_calc(integer);
+DROP FUNCTION ulist_labels_create(integer);
+DROP FUNCTION item_info(id vndbid, num int);
+DROP FUNCTION notify(iid vndbid, num integer, uid integer);
+DROP FUNCTION update_users_ulist_stats(integer);
+DROP FUNCTION user_getscryptargs(integer);
+DROP FUNCTION user_login(integer, bytea, bytea);
+DROP FUNCTION user_logout(integer, bytea);
+DROP FUNCTION user_isvalidsession(integer, bytea, session_type);
+DROP FUNCTION user_emailtoid(text);
+DROP FUNCTION user_resetpass(text, bytea);
+DROP FUNCTION user_setpass(integer, bytea, bytea);
+DROP FUNCTION user_isauth(integer, integer, bytea);
+DROP FUNCTION user_getmail(integer, integer, bytea);
+DROP FUNCTION user_setmail_token(integer, bytea, bytea, text);
+DROP FUNCTION user_setmail_confirm(integer, bytea);
+DROP FUNCTION user_setperm_usermod(integer, integer, bytea, boolean);
+DROP FUNCTION user_admin_setpass(integer, integer, bytea, bytea);
+DROP FUNCTION user_admin_setmail(integer, integer, bytea, text);
+\i sql/func.sql
+\i sql/editfunc.sql
+DROP TYPE edit_rettype;
+
+COMMIT;
+
+-- Need to do this analyze to ensure adding the foreign key constraints will use proper query plans.
+ANALYZE;
+\i sql/tableattrs.sql
+\i sql/perms.sql
+SELECT update_images_cache(NULL);