mirror of https://github.com/stashapp/stash.git
Change performer height to be numeric (#3060)
* Make height an int. Add height_cm field * Change UI to use height_cm * Use number fields for height/weight * Add migration note
This commit is contained in:
parent
b9e07ade92
commit
d2743cf5fb
|
@ -13,7 +13,7 @@ fragment SlimPerformerData on Performer {
|
|||
ethnicity
|
||||
hair_color
|
||||
eye_color
|
||||
height
|
||||
height_cm
|
||||
fake_tits
|
||||
career_length
|
||||
tattoos
|
||||
|
|
|
@ -10,7 +10,7 @@ fragment PerformerData on Performer {
|
|||
ethnicity
|
||||
country
|
||||
eye_color
|
||||
height
|
||||
height_cm
|
||||
measurements
|
||||
fake_tits
|
||||
career_length
|
||||
|
|
|
@ -60,7 +60,9 @@ input PerformerFilterType {
|
|||
"""Filter by eye color"""
|
||||
eye_color: StringCriterionInput
|
||||
"""Filter by height"""
|
||||
height: StringCriterionInput
|
||||
height: StringCriterionInput @deprecated(reason: "Use height_cm instead")
|
||||
"""Filter by height in cm"""
|
||||
height_cm: IntCriterionInput
|
||||
"""Filter by measurements"""
|
||||
measurements: StringCriterionInput
|
||||
"""Filter by fake tits value"""
|
||||
|
|
|
@ -19,7 +19,8 @@ type Performer {
|
|||
ethnicity: String
|
||||
country: String
|
||||
eye_color: String
|
||||
height: String
|
||||
height: String @deprecated(reason: "Use height_cm")
|
||||
height_cm: Int
|
||||
measurements: String
|
||||
fake_tits: String
|
||||
career_length: String
|
||||
|
@ -55,7 +56,9 @@ input PerformerCreateInput {
|
|||
ethnicity: String
|
||||
country: String
|
||||
eye_color: String
|
||||
height: String
|
||||
# height must be parsable into an integer
|
||||
height: String @deprecated(reason: "Use height_cm")
|
||||
height_cm: Int
|
||||
measurements: String
|
||||
fake_tits: String
|
||||
career_length: String
|
||||
|
@ -86,7 +89,9 @@ input PerformerUpdateInput {
|
|||
ethnicity: String
|
||||
country: String
|
||||
eye_color: String
|
||||
height: String
|
||||
# height must be parsable into an integer
|
||||
height: String @deprecated(reason: "Use height_cm")
|
||||
height_cm: Int
|
||||
measurements: String
|
||||
fake_tits: String
|
||||
career_length: String
|
||||
|
@ -117,7 +122,9 @@ input BulkPerformerUpdateInput {
|
|||
ethnicity: String
|
||||
country: String
|
||||
eye_color: String
|
||||
height: String
|
||||
# height must be parsable into an integer
|
||||
height: String @deprecated(reason: "Use height_cm")
|
||||
height_cm: Int
|
||||
measurements: String
|
||||
fake_tits: String
|
||||
career_length: String
|
||||
|
|
|
@ -2,6 +2,7 @@ package api
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/stashapp/stash/internal/api/urlbuilders"
|
||||
"github.com/stashapp/stash/pkg/gallery"
|
||||
|
@ -9,6 +10,18 @@ import (
|
|||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
func (r *performerResolver) Height(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Height != nil {
|
||||
ret := strconv.Itoa(*obj.Height)
|
||||
return &ret, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) HeightCm(ctx context.Context, obj *models.Performer) (*int, error) {
|
||||
return obj.Height, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Birthdate(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Birthdate != nil {
|
||||
ret := obj.Birthdate.String()
|
||||
|
|
|
@ -77,8 +77,15 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input PerformerC
|
|||
if input.EyeColor != nil {
|
||||
newPerformer.EyeColor = *input.EyeColor
|
||||
}
|
||||
if input.Height != nil {
|
||||
newPerformer.Height = *input.Height
|
||||
// prefer height_cm over height
|
||||
if input.HeightCm != nil {
|
||||
newPerformer.Height = input.HeightCm
|
||||
} else if input.Height != nil {
|
||||
h, err := strconv.Atoi(*input.Height)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid height: %s", *input.Height)
|
||||
}
|
||||
newPerformer.Height = &h
|
||||
}
|
||||
if input.Measurements != nil {
|
||||
newPerformer.Measurements = *input.Measurements
|
||||
|
@ -213,7 +220,16 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input PerformerU
|
|||
updatedPerformer.Country = translator.optionalString(input.Country, "country")
|
||||
updatedPerformer.EyeColor = translator.optionalString(input.EyeColor, "eye_color")
|
||||
updatedPerformer.Measurements = translator.optionalString(input.Measurements, "measurements")
|
||||
updatedPerformer.Height = translator.optionalString(input.Height, "height")
|
||||
// prefer height_cm over height
|
||||
if translator.hasField("height_cm") {
|
||||
updatedPerformer.Height = translator.optionalInt(input.HeightCm, "height_cm")
|
||||
} else if translator.hasField("height") {
|
||||
updatedPerformer.Height, err = translator.optionalIntFromString(input.Height, "height")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
updatedPerformer.Ethnicity = translator.optionalString(input.Ethnicity, "ethnicity")
|
||||
updatedPerformer.FakeTits = translator.optionalString(input.FakeTits, "fake_tits")
|
||||
updatedPerformer.CareerLength = translator.optionalString(input.CareerLength, "career_length")
|
||||
|
@ -317,7 +333,16 @@ func (r *mutationResolver) BulkPerformerUpdate(ctx context.Context, input BulkPe
|
|||
updatedPerformer.Ethnicity = translator.optionalString(input.Ethnicity, "ethnicity")
|
||||
updatedPerformer.Country = translator.optionalString(input.Country, "country")
|
||||
updatedPerformer.EyeColor = translator.optionalString(input.EyeColor, "eye_color")
|
||||
updatedPerformer.Height = translator.optionalString(input.Height, "height")
|
||||
// prefer height_cm over height
|
||||
if translator.hasField("height_cm") {
|
||||
updatedPerformer.Height = translator.optionalInt(input.HeightCm, "height_cm")
|
||||
} else if translator.hasField("height") {
|
||||
updatedPerformer.Height, err = translator.optionalIntFromString(input.Height, "height")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
updatedPerformer.Measurements = translator.optionalString(input.Measurements, "measurements")
|
||||
updatedPerformer.FakeTits = translator.optionalString(input.FakeTits, "fake_tits")
|
||||
updatedPerformer.CareerLength = translator.optionalString(input.CareerLength, "career_length")
|
||||
|
|
|
@ -84,7 +84,16 @@ func scrapedToPerformerInput(performer *models.ScrapedPerformer) models.Performe
|
|||
ret.HairColor = *performer.HairColor
|
||||
}
|
||||
if performer.Height != nil {
|
||||
ret.Height = *performer.Height
|
||||
h, err := strconv.Atoi(*performer.Height) // height is stored as an int
|
||||
if err == nil {
|
||||
ret.Height = &h
|
||||
}
|
||||
}
|
||||
if performer.Weight != nil {
|
||||
h, err := strconv.Atoi(*performer.Weight)
|
||||
if err == nil {
|
||||
ret.Weight = &h
|
||||
}
|
||||
}
|
||||
if performer.Measurements != nil {
|
||||
ret.Measurements = *performer.Measurements
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/models/mocks"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
|
@ -233,7 +234,7 @@ func Test_scrapedToPerformerInput(t *testing.T) {
|
|||
md5 := "b068931cc450442b63f5b3d276ea4297"
|
||||
|
||||
var stringValues []string
|
||||
for i := 0; i < 16; i++ {
|
||||
for i := 0; i < 17; i++ {
|
||||
stringValues = append(stringValues, strconv.Itoa(i))
|
||||
}
|
||||
|
||||
|
@ -244,6 +245,12 @@ func Test_scrapedToPerformerInput(t *testing.T) {
|
|||
return &ret
|
||||
}
|
||||
|
||||
nextIntVal := func() *int {
|
||||
ret := upTo
|
||||
upTo = (upTo + 1) % len(stringValues)
|
||||
return &ret
|
||||
}
|
||||
|
||||
dateToDatePtr := func(d models.Date) *models.Date {
|
||||
return &d
|
||||
}
|
||||
|
@ -265,6 +272,7 @@ func Test_scrapedToPerformerInput(t *testing.T) {
|
|||
EyeColor: nextVal(),
|
||||
HairColor: nextVal(),
|
||||
Height: nextVal(),
|
||||
Weight: nextVal(),
|
||||
Measurements: nextVal(),
|
||||
FakeTits: nextVal(),
|
||||
CareerLength: nextVal(),
|
||||
|
@ -284,7 +292,8 @@ func Test_scrapedToPerformerInput(t *testing.T) {
|
|||
Country: *nextVal(),
|
||||
EyeColor: *nextVal(),
|
||||
HairColor: *nextVal(),
|
||||
Height: *nextVal(),
|
||||
Height: nextIntVal(),
|
||||
Weight: nextIntVal(),
|
||||
Measurements: *nextVal(),
|
||||
FakeTits: *nextVal(),
|
||||
CareerLength: *nextVal(),
|
||||
|
@ -314,9 +323,7 @@ func Test_scrapedToPerformerInput(t *testing.T) {
|
|||
got.CreatedAt = time.Time{}
|
||||
got.UpdatedAt = got.CreatedAt
|
||||
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("scrapedToPerformerInput() = %v, want %v", got, tt.want)
|
||||
}
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package manager
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/pkg/hash/md5"
|
||||
|
@ -114,7 +115,16 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
|||
partial.Gender = models.NewOptionalString(*performer.Gender)
|
||||
}
|
||||
if performer.Height != nil && !excluded["height"] {
|
||||
partial.Height = models.NewOptionalString(*performer.Height)
|
||||
h, err := strconv.Atoi(*performer.Height)
|
||||
if err == nil {
|
||||
partial.Height = models.NewOptionalInt(h)
|
||||
}
|
||||
}
|
||||
if performer.Weight != nil && !excluded["weight"] {
|
||||
w, err := strconv.Atoi(*performer.Weight)
|
||||
if err == nil {
|
||||
partial.Weight = models.NewOptionalInt(w)
|
||||
}
|
||||
}
|
||||
if performer.Instagram != nil && !excluded["instagram"] {
|
||||
partial.Instagram = models.NewOptionalString(*performer.Instagram)
|
||||
|
@ -192,7 +202,8 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
|||
EyeColor: getString(performer.EyeColor),
|
||||
FakeTits: getString(performer.FakeTits),
|
||||
Gender: models.GenderEnum(getString(performer.Gender)),
|
||||
Height: getString(performer.Height),
|
||||
Height: getIntPtr(performer.Height),
|
||||
Weight: getIntPtr(performer.Weight),
|
||||
Instagram: getString(performer.Instagram),
|
||||
Measurements: getString(performer.Measurements),
|
||||
Name: *performer.Name,
|
||||
|
@ -261,3 +272,16 @@ func getString(val *string) string {
|
|||
return *val
|
||||
}
|
||||
}
|
||||
|
||||
func getIntPtr(val *string) *int {
|
||||
if val == nil {
|
||||
return nil
|
||||
} else {
|
||||
v, err := strconv.Atoi(*val)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &v
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,12 +85,30 @@ type StringCriterionInput struct {
|
|||
Modifier CriterionModifier `json:"modifier"`
|
||||
}
|
||||
|
||||
func (i StringCriterionInput) ValidModifier() bool {
|
||||
switch i.Modifier {
|
||||
case CriterionModifierEquals, CriterionModifierNotEquals, CriterionModifierIncludes, CriterionModifierExcludes, CriterionModifierMatchesRegex, CriterionModifierNotMatchesRegex,
|
||||
CriterionModifierIsNull, CriterionModifierNotNull:
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type IntCriterionInput struct {
|
||||
Value int `json:"value"`
|
||||
Value2 *int `json:"value2"`
|
||||
Modifier CriterionModifier `json:"modifier"`
|
||||
}
|
||||
|
||||
func (i IntCriterionInput) ValidModifier() bool {
|
||||
switch i.Modifier {
|
||||
case CriterionModifierEquals, CriterionModifierNotEquals, CriterionModifierGreaterThan, CriterionModifierLessThan, CriterionModifierIsNull, CriterionModifierNotNull, CriterionModifierBetween, CriterionModifierNotBetween:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ResolutionCriterionInput struct {
|
||||
Value ResolutionEnum `json:"value"`
|
||||
Modifier CriterionModifier `json:"modifier"`
|
||||
|
|
|
@ -11,15 +11,16 @@ import (
|
|||
)
|
||||
|
||||
type Performer struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Gender string `json:"gender,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Twitter string `json:"twitter,omitempty"`
|
||||
Instagram string `json:"instagram,omitempty"`
|
||||
Birthdate string `json:"birthdate,omitempty"`
|
||||
Ethnicity string `json:"ethnicity,omitempty"`
|
||||
Country string `json:"country,omitempty"`
|
||||
EyeColor string `json:"eye_color,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Gender string `json:"gender,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Twitter string `json:"twitter,omitempty"`
|
||||
Instagram string `json:"instagram,omitempty"`
|
||||
Birthdate string `json:"birthdate,omitempty"`
|
||||
Ethnicity string `json:"ethnicity,omitempty"`
|
||||
Country string `json:"country,omitempty"`
|
||||
EyeColor string `json:"eye_color,omitempty"`
|
||||
// this should be int, but keeping string for backwards compatibility
|
||||
Height string `json:"height,omitempty"`
|
||||
Measurements string `json:"measurements,omitempty"`
|
||||
FakeTits string `json:"fake_tits,omitempty"`
|
||||
|
|
|
@ -18,7 +18,7 @@ type Performer struct {
|
|||
Ethnicity string `json:"ethnicity"`
|
||||
Country string `json:"country"`
|
||||
EyeColor string `json:"eye_color"`
|
||||
Height string `json:"height"`
|
||||
Height *int `json:"height"`
|
||||
Measurements string `json:"measurements"`
|
||||
FakeTits string `json:"fake_tits"`
|
||||
CareerLength string `json:"career_length"`
|
||||
|
@ -50,7 +50,7 @@ type PerformerPartial struct {
|
|||
Ethnicity OptionalString
|
||||
Country OptionalString
|
||||
EyeColor OptionalString
|
||||
Height OptionalString
|
||||
Height OptionalInt
|
||||
Measurements OptionalString
|
||||
FakeTits OptionalString
|
||||
CareerLength OptionalString
|
||||
|
|
|
@ -79,8 +79,10 @@ type PerformerFilterType struct {
|
|||
Country *StringCriterionInput `json:"country"`
|
||||
// Filter by eye color
|
||||
EyeColor *StringCriterionInput `json:"eye_color"`
|
||||
// Filter by height
|
||||
// Filter by height - deprecated: use height_cm instead
|
||||
Height *StringCriterionInput `json:"height"`
|
||||
// Filter by height in centimeters
|
||||
HeightCm *IntCriterionInput `json:"height_cm"`
|
||||
// Filter by measurements
|
||||
Measurements *StringCriterionInput `json:"measurements"`
|
||||
// Filter by fake tits value
|
||||
|
|
|
@ -3,6 +3,7 @@ package performer
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/models/json"
|
||||
|
@ -24,7 +25,6 @@ func ToJSON(ctx context.Context, reader ImageStashIDGetter, performer *models.Pe
|
|||
Ethnicity: performer.Ethnicity,
|
||||
Country: performer.Country,
|
||||
EyeColor: performer.EyeColor,
|
||||
Height: performer.Height,
|
||||
Measurements: performer.Measurements,
|
||||
FakeTits: performer.FakeTits,
|
||||
CareerLength: performer.CareerLength,
|
||||
|
@ -50,6 +50,11 @@ func ToJSON(ctx context.Context, reader ImageStashIDGetter, performer *models.Pe
|
|||
if performer.DeathDate != nil {
|
||||
newPerformerJSON.DeathDate = performer.DeathDate.String()
|
||||
}
|
||||
|
||||
if performer.Height != nil {
|
||||
newPerformerJSON.Height = strconv.Itoa(*performer.Height)
|
||||
}
|
||||
|
||||
if performer.Weight != nil {
|
||||
newPerformerJSON.Weight = *performer.Weight
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package performer
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"github.com/stashapp/stash/pkg/hash/md5"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
|
@ -30,7 +31,6 @@ const (
|
|||
eyeColor = "eyeColor"
|
||||
fakeTits = "fakeTits"
|
||||
gender = "gender"
|
||||
height = "height"
|
||||
instagram = "instagram"
|
||||
measurements = "measurements"
|
||||
piercings = "piercings"
|
||||
|
@ -44,6 +44,7 @@ const (
|
|||
|
||||
var (
|
||||
rating = 5
|
||||
height = 123
|
||||
weight = 60
|
||||
)
|
||||
|
||||
|
@ -82,7 +83,7 @@ func createFullPerformer(id int, name string) *models.Performer {
|
|||
FakeTits: fakeTits,
|
||||
Favorite: true,
|
||||
Gender: gender,
|
||||
Height: height,
|
||||
Height: &height,
|
||||
Instagram: instagram,
|
||||
Measurements: measurements,
|
||||
Piercings: piercings,
|
||||
|
@ -120,7 +121,7 @@ func createFullJSONPerformer(name string, image string) *jsonschema.Performer {
|
|||
FakeTits: fakeTits,
|
||||
Favorite: true,
|
||||
Gender: gender,
|
||||
Height: height,
|
||||
Height: strconv.Itoa(height),
|
||||
Instagram: instagram,
|
||||
Measurements: measurements,
|
||||
Piercings: piercings,
|
||||
|
|
|
@ -3,9 +3,11 @@ package performer
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/stashapp/stash/pkg/hash/md5"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/models/jsonschema"
|
||||
"github.com/stashapp/stash/pkg/sliceutil/stringslice"
|
||||
|
@ -194,7 +196,6 @@ func performerJSONToPerformer(performerJSON jsonschema.Performer) models.Perform
|
|||
Ethnicity: performerJSON.Ethnicity,
|
||||
Country: performerJSON.Country,
|
||||
EyeColor: performerJSON.EyeColor,
|
||||
Height: performerJSON.Height,
|
||||
Measurements: performerJSON.Measurements,
|
||||
FakeTits: performerJSON.FakeTits,
|
||||
CareerLength: performerJSON.CareerLength,
|
||||
|
@ -235,5 +236,14 @@ func performerJSONToPerformer(performerJSON jsonschema.Performer) models.Perform
|
|||
newPerformer.Weight = &performerJSON.Weight
|
||||
}
|
||||
|
||||
if performerJSON.Height != "" {
|
||||
h, err := strconv.Atoi(performerJSON.Height)
|
||||
if err == nil {
|
||||
newPerformer.Height = &h
|
||||
} else {
|
||||
logger.Warnf("error parsing height %q: %v", performerJSON.Height, err)
|
||||
}
|
||||
}
|
||||
|
||||
return newPerformer
|
||||
}
|
||||
|
|
|
@ -975,8 +975,9 @@ func (c Client) SubmitPerformerDraft(ctx context.Context, performer *models.Perf
|
|||
if performer.HairColor != "" {
|
||||
draft.HairColor = &performer.HairColor
|
||||
}
|
||||
if performer.Height != "" {
|
||||
draft.Height = &performer.Height
|
||||
if performer.Height != nil {
|
||||
v := strconv.Itoa(*performer.Height)
|
||||
draft.Height = &v
|
||||
}
|
||||
if performer.Measurements != "" {
|
||||
draft.Measurements = &performer.Measurements
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
"github.com/stashapp/stash/pkg/logger"
|
||||
)
|
||||
|
||||
var appSchemaVersion uint = 38
|
||||
var appSchemaVersion uint = 39
|
||||
|
||||
//go:embed migrations/*.sql
|
||||
var migrationsBox embed.FS
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
-- add primary keys to association tables that are missing them
|
||||
PRAGMA foreign_keys=OFF;
|
||||
|
||||
CREATE TABLE `performers_new` (
|
||||
`id` integer not null primary key autoincrement,
|
||||
`checksum` varchar(255) not null,
|
||||
`name` varchar(255),
|
||||
`gender` varchar(20),
|
||||
`url` varchar(255),
|
||||
`twitter` varchar(255),
|
||||
`instagram` varchar(255),
|
||||
`birthdate` date,
|
||||
`ethnicity` varchar(255),
|
||||
`country` varchar(255),
|
||||
`eye_color` varchar(255),
|
||||
-- changed from varchar(255)
|
||||
`height` int,
|
||||
`measurements` varchar(255),
|
||||
`fake_tits` varchar(255),
|
||||
`career_length` varchar(255),
|
||||
`tattoos` varchar(255),
|
||||
`piercings` varchar(255),
|
||||
`aliases` varchar(255),
|
||||
`favorite` boolean not null default '0',
|
||||
`created_at` datetime not null,
|
||||
`updated_at` datetime not null,
|
||||
`details` text,
|
||||
`death_date` date,
|
||||
`hair_color` varchar(255),
|
||||
`weight` integer,
|
||||
`rating` tinyint,
|
||||
`ignore_auto_tag` boolean not null default '0'
|
||||
);
|
||||
|
||||
INSERT INTO `performers_new`
|
||||
(
|
||||
`id`,
|
||||
`checksum`,
|
||||
`name`,
|
||||
`gender`,
|
||||
`url`,
|
||||
`twitter`,
|
||||
`instagram`,
|
||||
`birthdate`,
|
||||
`ethnicity`,
|
||||
`country`,
|
||||
`eye_color`,
|
||||
`height`,
|
||||
`measurements`,
|
||||
`fake_tits`,
|
||||
`career_length`,
|
||||
`tattoos`,
|
||||
`piercings`,
|
||||
`aliases`,
|
||||
`favorite`,
|
||||
`created_at`,
|
||||
`updated_at`,
|
||||
`details`,
|
||||
`death_date`,
|
||||
`hair_color`,
|
||||
`weight`,
|
||||
`rating`,
|
||||
`ignore_auto_tag`
|
||||
)
|
||||
SELECT
|
||||
`id`,
|
||||
`checksum`,
|
||||
`name`,
|
||||
`gender`,
|
||||
`url`,
|
||||
`twitter`,
|
||||
`instagram`,
|
||||
`birthdate`,
|
||||
`ethnicity`,
|
||||
`country`,
|
||||
`eye_color`,
|
||||
CASE `height`
|
||||
WHEN '' THEN NULL
|
||||
WHEN NULL THEN NULL
|
||||
ELSE CAST(`height` as int)
|
||||
END,
|
||||
`measurements`,
|
||||
`fake_tits`,
|
||||
`career_length`,
|
||||
`tattoos`,
|
||||
`piercings`,
|
||||
`aliases`,
|
||||
`favorite`,
|
||||
`created_at`,
|
||||
`updated_at`,
|
||||
`details`,
|
||||
`death_date`,
|
||||
`hair_color`,
|
||||
`weight`,
|
||||
`rating`,
|
||||
`ignore_auto_tag`
|
||||
FROM `performers`;
|
||||
|
||||
DROP TABLE `performers`;
|
||||
ALTER TABLE `performers_new` rename to `performers`;
|
||||
|
||||
CREATE UNIQUE INDEX `performers_checksum_unique` on `performers` (`checksum`);
|
||||
CREATE INDEX `index_performers_on_name` on `performers` (`name`);
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/doug-martin/goqu/v9"
|
||||
|
@ -33,7 +34,7 @@ type performerRow struct {
|
|||
Ethnicity zero.String `db:"ethnicity"`
|
||||
Country zero.String `db:"country"`
|
||||
EyeColor zero.String `db:"eye_color"`
|
||||
Height zero.String `db:"height"`
|
||||
Height null.Int `db:"height"`
|
||||
Measurements zero.String `db:"measurements"`
|
||||
FakeTits zero.String `db:"fake_tits"`
|
||||
CareerLength zero.String `db:"career_length"`
|
||||
|
@ -67,7 +68,7 @@ func (r *performerRow) fromPerformer(o models.Performer) {
|
|||
r.Ethnicity = zero.StringFrom(o.Ethnicity)
|
||||
r.Country = zero.StringFrom(o.Country)
|
||||
r.EyeColor = zero.StringFrom(o.EyeColor)
|
||||
r.Height = zero.StringFrom(o.Height)
|
||||
r.Height = intFromPtr(o.Height)
|
||||
r.Measurements = zero.StringFrom(o.Measurements)
|
||||
r.FakeTits = zero.StringFrom(o.FakeTits)
|
||||
r.CareerLength = zero.StringFrom(o.CareerLength)
|
||||
|
@ -100,7 +101,7 @@ func (r *performerRow) resolve() *models.Performer {
|
|||
Ethnicity: r.Ethnicity.String,
|
||||
Country: r.Country.String,
|
||||
EyeColor: r.EyeColor.String,
|
||||
Height: r.Height.String,
|
||||
Height: nullIntPtr(r.Height),
|
||||
Measurements: r.Measurements.String,
|
||||
FakeTits: r.FakeTits.String,
|
||||
CareerLength: r.CareerLength.String,
|
||||
|
@ -136,7 +137,7 @@ func (r *performerRowRecord) fromPartial(o models.PerformerPartial) {
|
|||
r.setNullString("ethnicity", o.Ethnicity)
|
||||
r.setNullString("country", o.Country)
|
||||
r.setNullString("eye_color", o.EyeColor)
|
||||
r.setNullString("height", o.Height)
|
||||
r.setNullInt("height", o.Height)
|
||||
r.setNullString("measurements", o.Measurements)
|
||||
r.setNullString("fake_tits", o.FakeTits)
|
||||
r.setNullString("career_length", o.CareerLength)
|
||||
|
@ -445,6 +446,22 @@ func (qb *PerformerStore) validateFilter(filter *models.PerformerFilterType) err
|
|||
return qb.validateFilter(filter.Not)
|
||||
}
|
||||
|
||||
// if legacy height filter used, ensure only supported modifiers are used
|
||||
if filter.Height != nil {
|
||||
// treat as an int filter
|
||||
intCrit := &models.IntCriterionInput{
|
||||
Modifier: filter.Height.Modifier,
|
||||
}
|
||||
if !intCrit.ValidModifier() {
|
||||
return fmt.Errorf("invalid height modifier: %s", filter.Height.Modifier)
|
||||
}
|
||||
|
||||
// ensure value is a valid number
|
||||
if _, err := strconv.Atoi(filter.Height.Value); err != nil {
|
||||
return fmt.Errorf("invalid height value: %s", filter.Height.Value)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -483,7 +500,19 @@ func (qb *PerformerStore) makeFilter(ctx context.Context, filter *models.Perform
|
|||
query.handleCriterion(ctx, stringCriterionHandler(filter.Ethnicity, tableName+".ethnicity"))
|
||||
query.handleCriterion(ctx, stringCriterionHandler(filter.Country, tableName+".country"))
|
||||
query.handleCriterion(ctx, stringCriterionHandler(filter.EyeColor, tableName+".eye_color"))
|
||||
query.handleCriterion(ctx, stringCriterionHandler(filter.Height, tableName+".height"))
|
||||
|
||||
// special handler for legacy height filter
|
||||
heightCmCrit := filter.HeightCm
|
||||
if heightCmCrit == nil && filter.Height != nil {
|
||||
heightCm, _ := strconv.Atoi(filter.Height.Value) // already validated
|
||||
heightCmCrit = &models.IntCriterionInput{
|
||||
Value: heightCm,
|
||||
Modifier: filter.Height.Modifier,
|
||||
}
|
||||
}
|
||||
|
||||
query.handleCriterion(ctx, intCriterionHandler(heightCmCrit, tableName+".height", nil))
|
||||
|
||||
query.handleCriterion(ctx, stringCriterionHandler(filter.Measurements, tableName+".measurements"))
|
||||
query.handleCriterion(ctx, stringCriterionHandler(filter.FakeTits, tableName+".fake_tits"))
|
||||
query.handleCriterion(ctx, stringCriterionHandler(filter.CareerLength, tableName+".career_length"))
|
||||
|
|
|
@ -30,7 +30,7 @@ func Test_PerformerStore_Update(t *testing.T) {
|
|||
ethnicity = "ethnicity"
|
||||
country = "country"
|
||||
eyeColor = "eyeColor"
|
||||
height = "height"
|
||||
height = 134
|
||||
measurements = "measurements"
|
||||
fakeTits = "fakeTits"
|
||||
careerLength = "careerLength"
|
||||
|
@ -67,7 +67,7 @@ func Test_PerformerStore_Update(t *testing.T) {
|
|||
Ethnicity: ethnicity,
|
||||
Country: country,
|
||||
EyeColor: eyeColor,
|
||||
Height: height,
|
||||
Height: &height,
|
||||
Measurements: measurements,
|
||||
FakeTits: fakeTits,
|
||||
CareerLength: careerLength,
|
||||
|
@ -133,7 +133,7 @@ func Test_PerformerStore_UpdatePartial(t *testing.T) {
|
|||
ethnicity = "ethnicity"
|
||||
country = "country"
|
||||
eyeColor = "eyeColor"
|
||||
height = "height"
|
||||
height = 143
|
||||
measurements = "measurements"
|
||||
fakeTits = "fakeTits"
|
||||
careerLength = "careerLength"
|
||||
|
@ -172,7 +172,7 @@ func Test_PerformerStore_UpdatePartial(t *testing.T) {
|
|||
Ethnicity: models.NewOptionalString(ethnicity),
|
||||
Country: models.NewOptionalString(country),
|
||||
EyeColor: models.NewOptionalString(eyeColor),
|
||||
Height: models.NewOptionalString(height),
|
||||
Height: models.NewOptionalInt(height),
|
||||
Measurements: models.NewOptionalString(measurements),
|
||||
FakeTits: models.NewOptionalString(fakeTits),
|
||||
CareerLength: models.NewOptionalString(careerLength),
|
||||
|
@ -201,7 +201,7 @@ func Test_PerformerStore_UpdatePartial(t *testing.T) {
|
|||
Ethnicity: ethnicity,
|
||||
Country: country,
|
||||
EyeColor: eyeColor,
|
||||
Height: height,
|
||||
Height: &height,
|
||||
Measurements: measurements,
|
||||
FakeTits: fakeTits,
|
||||
CareerLength: careerLength,
|
||||
|
@ -506,29 +506,62 @@ func TestPerformerIllegalQuery(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
performerFilter := &models.PerformerFilterType{
|
||||
And: &subFilter,
|
||||
Or: &subFilter,
|
||||
tests := []struct {
|
||||
name string
|
||||
filter models.PerformerFilterType
|
||||
}{
|
||||
{
|
||||
// And and Or in the same filter
|
||||
"AndOr",
|
||||
models.PerformerFilterType{
|
||||
And: &subFilter,
|
||||
Or: &subFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
// And and Not in the same filter
|
||||
"AndNot",
|
||||
models.PerformerFilterType{
|
||||
And: &subFilter,
|
||||
Not: &subFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Or and Not in the same filter
|
||||
"OrNot",
|
||||
models.PerformerFilterType{
|
||||
Or: &subFilter,
|
||||
Not: &subFilter,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid height modifier",
|
||||
models.PerformerFilterType{
|
||||
Height: &models.StringCriterionInput{
|
||||
Modifier: models.CriterionModifierMatchesRegex,
|
||||
Value: "123",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid height value",
|
||||
models.PerformerFilterType{
|
||||
Height: &models.StringCriterionInput{
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
Value: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
withTxn(func(ctx context.Context) error {
|
||||
sqb := db.Performer
|
||||
sqb := db.Performer
|
||||
|
||||
_, _, err := sqb.Query(ctx, performerFilter, nil)
|
||||
assert.NotNil(err)
|
||||
|
||||
performerFilter.Or = nil
|
||||
performerFilter.Not = &subFilter
|
||||
_, _, err = sqb.Query(ctx, performerFilter, nil)
|
||||
assert.NotNil(err)
|
||||
|
||||
performerFilter.And = nil
|
||||
performerFilter.Or = &subFilter
|
||||
_, _, err = sqb.Query(ctx, performerFilter, nil)
|
||||
assert.NotNil(err)
|
||||
|
||||
return nil
|
||||
})
|
||||
for _, tt := range tests {
|
||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||
_, _, err := sqb.Query(ctx, &tt.filter, nil)
|
||||
assert.NotNil(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPerformerQueryIgnoreAutoTag(t *testing.T) {
|
||||
|
|
|
@ -178,7 +178,7 @@ func getIntWhereClause(column string, modifier models.CriterionModifier, value i
|
|||
return fmt.Sprintf("%s > ?", column), args
|
||||
}
|
||||
|
||||
panic("unsupported int modifier type")
|
||||
panic("unsupported int modifier type " + modifier)
|
||||
}
|
||||
|
||||
// returns where clause and having clause
|
||||
|
|
|
@ -71,11 +71,11 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
|
|||
);
|
||||
}
|
||||
|
||||
const formatHeight = (height?: string | null) => {
|
||||
const formatHeight = (height?: number | null) => {
|
||||
if (!height) {
|
||||
return "";
|
||||
}
|
||||
return intl.formatNumber(Number.parseInt(height, 10), {
|
||||
return intl.formatNumber(height, {
|
||||
style: "unit",
|
||||
unit: "centimeter",
|
||||
unitDisplay: "narrow",
|
||||
|
@ -120,7 +120,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
|
|||
getCountryByISO(performer.country, intl.locale) ?? performer.country
|
||||
}
|
||||
/>
|
||||
<TextField id="height" value={formatHeight(performer.height)} />
|
||||
<TextField id="height" value={formatHeight(performer.height_cm)} />
|
||||
<TextField id="weight" value={formatWeight(performer.weight)} />
|
||||
<TextField id="measurements" value={performer.measurements} />
|
||||
<TextField id="fake_tits" value={performer.fake_tits} />
|
||||
|
|
|
@ -106,7 +106,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
ethnicity: yup.string().optional(),
|
||||
eye_color: yup.string().optional(),
|
||||
country: yup.string().optional(),
|
||||
height: yup.string().optional(),
|
||||
height_cm: yup.number().optional(),
|
||||
measurements: yup.string().optional(),
|
||||
fake_tits: yup.string().optional(),
|
||||
career_length: yup.string().optional(),
|
||||
|
@ -133,7 +133,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
ethnicity: performer.ethnicity ?? "",
|
||||
eye_color: performer.eye_color ?? "",
|
||||
country: performer.country ?? "",
|
||||
height: performer.height ?? "",
|
||||
height_cm: performer.height_cm ?? undefined,
|
||||
measurements: performer.measurements ?? "",
|
||||
fake_tits: performer.fake_tits ?? "",
|
||||
career_length: performer.career_length ?? "",
|
||||
|
@ -279,7 +279,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
formik.setFieldValue("eye_color", state.eye_color);
|
||||
}
|
||||
if (state.height) {
|
||||
formik.setFieldValue("height", state.height);
|
||||
formik.setFieldValue("height_cm", parseInt(state.height, 10));
|
||||
}
|
||||
if (state.measurements) {
|
||||
formik.setFieldValue("measurements", state.measurements);
|
||||
|
@ -445,7 +445,8 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
return {
|
||||
...values,
|
||||
gender: stringToGender(values.gender) ?? null,
|
||||
weight: Number(values.weight),
|
||||
height_cm: values.height_cm ? Number(values.height_cm) : null,
|
||||
weight: values.weight ? Number(values.weight) : null,
|
||||
id: performer.id ?? "",
|
||||
};
|
||||
}
|
||||
|
@ -454,7 +455,8 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
return {
|
||||
...values,
|
||||
gender: stringToGender(values.gender),
|
||||
weight: Number(values.weight),
|
||||
height_cm: values.height_cm ? Number(values.height_cm) : null,
|
||||
weight: values.weight ? Number(values.weight) : null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -797,16 +799,26 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
);
|
||||
}
|
||||
|
||||
function renderTextField(field: string, title: string, placeholder?: string) {
|
||||
function renderField(
|
||||
field: string,
|
||||
props?: {
|
||||
messageID?: string;
|
||||
placeholder?: string;
|
||||
type?: string;
|
||||
}
|
||||
) {
|
||||
const title = intl.formatMessage({ id: props?.messageID ?? field });
|
||||
|
||||
return (
|
||||
<Form.Group controlId={field} as={Row}>
|
||||
<Form.Label column xs={labelXS} xl={labelXL}>
|
||||
<FormattedMessage id={field} defaultMessage={title} />
|
||||
{title}
|
||||
</Form.Label>
|
||||
<Col xs={fieldXS} xl={fieldXL}>
|
||||
<Form.Control
|
||||
type={props?.type ?? "text"}
|
||||
className="text-input"
|
||||
placeholder={placeholder ?? title}
|
||||
placeholder={props?.placeholder ?? title}
|
||||
{...formik.getFieldProps(field)}
|
||||
isInvalid={!!formik.getFieldMeta(field).error}
|
||||
/>
|
||||
|
@ -877,8 +889,8 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
</Col>
|
||||
</Form.Group>
|
||||
|
||||
{renderTextField("birthdate", "Birthdate", "YYYY-MM-DD")}
|
||||
{renderTextField("death_date", "Death Date", "YYYY-MM-DD")}
|
||||
{renderField("birthdate", { placeholder: "YYYY-MM-DD" })}
|
||||
{renderField("death_date", { placeholder: "YYYY-MM-DD" })}
|
||||
|
||||
<Form.Group as={Row}>
|
||||
<Form.Label column xs={labelXS} xl={labelXL}>
|
||||
|
@ -892,13 +904,20 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
</Col>
|
||||
</Form.Group>
|
||||
|
||||
{renderTextField("ethnicity", "Ethnicity")}
|
||||
{renderTextField("hair_color", "Hair Color")}
|
||||
{renderTextField("eye_color", "Eye Color")}
|
||||
{renderTextField("height", "Height (cm)")}
|
||||
{renderTextField("weight", "Weight (kg)")}
|
||||
{renderTextField("measurements", "Measurements")}
|
||||
{renderTextField("fake_tits", "Fake Tits")}
|
||||
{renderField("ethnicity")}
|
||||
{renderField("hair_color")}
|
||||
{renderField("eye_color")}
|
||||
{renderField("height_cm", {
|
||||
type: "number",
|
||||
messageID: "height",
|
||||
placeholder: intl.formatMessage({ id: "height_cm" }),
|
||||
})}
|
||||
{renderField("weight", {
|
||||
type: "number",
|
||||
placeholder: intl.formatMessage({ id: "weight_kg" }),
|
||||
})}
|
||||
{renderField("measurements")}
|
||||
{renderField("fake_tits")}
|
||||
|
||||
<Form.Group controlId="tattoos" as={Row}>
|
||||
<Form.Label column sm={labelXS} xl={labelXL}>
|
||||
|
@ -928,7 +947,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
</Col>
|
||||
</Form.Group>
|
||||
|
||||
{renderTextField("career_length", "Career Length")}
|
||||
{renderField("career_length")}
|
||||
|
||||
<Form.Group controlId="url" as={Row}>
|
||||
<Form.Label column xs={labelXS} xl={labelXL}>
|
||||
|
@ -943,8 +962,8 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
</Col>
|
||||
</Form.Group>
|
||||
|
||||
{renderTextField("twitter", "Twitter")}
|
||||
{renderTextField("instagram", "Instagram")}
|
||||
{renderField("twitter")}
|
||||
{renderField("instagram")}
|
||||
<Form.Group controlId="details" as={Row}>
|
||||
<Form.Label column sm={labelXS} xl={labelXL}>
|
||||
<FormattedMessage id="details" />
|
||||
|
|
|
@ -196,7 +196,10 @@ export const PerformerScrapeDialog: React.FC<IPerformerScrapeDialogProps> = (
|
|||
new ScrapeResult<string>(props.performer.eye_color, props.scraped.eye_color)
|
||||
);
|
||||
const [height, setHeight] = useState<ScrapeResult<string>>(
|
||||
new ScrapeResult<string>(props.performer.height, props.scraped.height)
|
||||
new ScrapeResult<string>(
|
||||
props.performer.height_cm?.toString(),
|
||||
props.scraped.height
|
||||
)
|
||||
);
|
||||
const [weight, setWeight] = useState<ScrapeResult<string>>(
|
||||
new ScrapeResult<string>(
|
||||
|
|
|
@ -58,7 +58,7 @@ export const PerformerListTable: React.FC<IPerformerListTableProps> = (
|
|||
</Link>
|
||||
</td>
|
||||
<td>{performer.birthdate}</td>
|
||||
<td>{performer.height}</td>
|
||||
<td>{performer.height_cm}</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ const PerformerModal: React.FC<IPerformerModalProps> = ({
|
|||
ethnicity: performer.ethnicity,
|
||||
eye_color: performer.eye_color,
|
||||
country: performer.country,
|
||||
height: performer.height,
|
||||
height_cm: Number.parseFloat(performer.height ?? "") ?? undefined,
|
||||
measurements: performer.measurements,
|
||||
fake_tits: performer.fake_tits,
|
||||
career_length: performer.career_length,
|
||||
|
@ -153,6 +153,10 @@ const PerformerModal: React.FC<IPerformerModalProps> = ({
|
|||
performerData.weight = undefined;
|
||||
}
|
||||
|
||||
if (Number.isNaN(performerData.height ?? 0)) {
|
||||
performerData.height = undefined;
|
||||
}
|
||||
|
||||
if (performer.tags) {
|
||||
performerData.tag_ids = performer.tags
|
||||
.map((t) => t.stored_id)
|
||||
|
|
|
@ -1194,7 +1194,7 @@ export const makePerformerCreateInput = (toCreate: GQL.ScrapedPerformer) => {
|
|||
ethnicity: toCreate.ethnicity,
|
||||
country: toCreate.country,
|
||||
eye_color: toCreate.eye_color,
|
||||
height: toCreate.height,
|
||||
height_cm: toCreate.height ? Number(toCreate.height) : undefined,
|
||||
measurements: toCreate.measurements,
|
||||
fake_tits: toCreate.fake_tits,
|
||||
career_length: toCreate.career_length,
|
||||
|
|
|
@ -3,5 +3,11 @@
|
|||
* Added selector for Country field. ([#1922](https://github.com/stashapp/stash/pull/1922))
|
||||
* Added tag description filter criterion. ([#3011](https://github.com/stashapp/stash/pull/3011))
|
||||
|
||||
### 🎨 Improvements
|
||||
* Changed Performer height to be numeric, and changed filtering accordingly. ((#3060)[https://github.com/stashapp/stash/pull/3060])
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Scene Player no longer always resumes playing when seeking. ([#3020](https://github.com/stashapp/stash/pull/3020))
|
||||
* Fixed space bar sometimes no playing/pausing the scene player. ([#3020](https://github.com/stashapp/stash/pull/3020))
|
||||
* Fixed scrubber thumbnails not disappearing when seeking on mobile. ([#3020](https://github.com/stashapp/stash/pull/3020))
|
||||
* Fix path filter behaviour to be consistent with previous behaviour. ([#3041](https://github.com/stashapp/stash/pull/3041))
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
This migration changes performer height values from strings to numbers. Non-numeric performer height values **will be erased during this migration**.
|
|
@ -1,7 +1,9 @@
|
|||
import migration32 from "./32.md";
|
||||
import migration38 from "./38.md";
|
||||
|
||||
type Module = typeof migration32;
|
||||
|
||||
export const migrationNotes: Record<number, Module> = {
|
||||
32: migration32,
|
||||
38: migration38,
|
||||
};
|
||||
|
|
|
@ -807,6 +807,7 @@
|
|||
},
|
||||
"hasMarkers": "Has Markers",
|
||||
"height": "Height",
|
||||
"height_cm": "Height (cm)",
|
||||
"help": "Help",
|
||||
"ignore_auto_tag": "Ignore Auto Tag",
|
||||
"image": "Image",
|
||||
|
@ -1065,6 +1066,7 @@
|
|||
"videos": "Videos",
|
||||
"view_all": "View All",
|
||||
"weight": "Weight",
|
||||
"weight_kg": "Weight (kg)",
|
||||
"years_old": "years old",
|
||||
"zip_file_count": "Zip File Count"
|
||||
}
|
||||
|
|
|
@ -147,10 +147,14 @@ export function makeCriteria(type: CriterionType = "none") {
|
|||
return new DuplicatedCriterion();
|
||||
case "country":
|
||||
return new CountryCriterion();
|
||||
case "height":
|
||||
case "height_cm":
|
||||
return new NumberCriterion(
|
||||
new NumberCriterionOption("height", "height_cm", type)
|
||||
);
|
||||
case "ethnicity":
|
||||
case "hair_color":
|
||||
case "eye_color":
|
||||
case "height":
|
||||
case "measurements":
|
||||
case "fake_tits":
|
||||
case "career_length":
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
createMandatoryNumberCriterionOption,
|
||||
createStringCriterionOption,
|
||||
createBooleanCriterionOption,
|
||||
NumberCriterionOption,
|
||||
} from "./criteria/criterion";
|
||||
import { FavoriteCriterionOption } from "./criteria/favorite";
|
||||
import { GenderCriterionOption } from "./criteria/gender";
|
||||
|
@ -58,7 +59,6 @@ const stringCriteria: CriterionType[] = [
|
|||
"country",
|
||||
"hair_color",
|
||||
"eye_color",
|
||||
"height",
|
||||
"measurements",
|
||||
"fake_tits",
|
||||
"career_length",
|
||||
|
@ -81,6 +81,7 @@ const criterionOptions = [
|
|||
createMandatoryNumberCriterionOption("image_count"),
|
||||
createMandatoryNumberCriterionOption("gallery_count"),
|
||||
createBooleanCriterionOption("ignore_auto_tag"),
|
||||
new NumberCriterionOption("height", "height_cm", "height_cm"),
|
||||
...numberCriteria.map((c) => createNumberCriterionOption(c)),
|
||||
...stringCriteria.map((c) => createStringCriterionOption(c)),
|
||||
];
|
||||
|
|
|
@ -88,6 +88,7 @@ export type CriterionType =
|
|||
| "hair_color"
|
||||
| "eye_color"
|
||||
| "height"
|
||||
| "height_cm"
|
||||
| "weight"
|
||||
| "measurements"
|
||||
| "fake_tits"
|
||||
|
|
Loading…
Reference in New Issue