Add penis length and circumcision stats to performers. (#3627)

* Add penis length stat to performers.
* Modified the UI to display and edit the stat.
* Added the ability to filter floats to allow filtering by penis length.
* Add circumcision stat to performer.
* Refactor enum filtering
* Change boolean filter to radio buttons
* Return null for empty enum values
---------
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
departure18
2023-05-24 04:19:35 +01:00
committed by GitHub
parent 58a6c22072
commit 776c7e6c35
52 changed files with 1051 additions and 184 deletions

View File

@@ -52,6 +52,8 @@ func Test_PerformerStore_Create(t *testing.T) {
height = 134
measurements = "measurements"
fakeTits = "fakeTits"
penisLength = 1.23
circumcised = models.CircumisedEnumCut
careerLength = "careerLength"
tattoos = "tattoos"
piercings = "piercings"
@@ -81,7 +83,7 @@ func Test_PerformerStore_Create(t *testing.T) {
models.Performer{
Name: name,
Disambiguation: disambiguation,
Gender: gender,
Gender: &gender,
URL: url,
Twitter: twitter,
Instagram: instagram,
@@ -92,6 +94,8 @@ func Test_PerformerStore_Create(t *testing.T) {
Height: &height,
Measurements: measurements,
FakeTits: fakeTits,
PenisLength: &penisLength,
Circumcised: &circumcised,
CareerLength: careerLength,
Tattoos: tattoos,
Piercings: piercings,
@@ -196,6 +200,8 @@ func Test_PerformerStore_Update(t *testing.T) {
height = 134
measurements = "measurements"
fakeTits = "fakeTits"
penisLength = 1.23
circumcised = models.CircumisedEnumCut
careerLength = "careerLength"
tattoos = "tattoos"
piercings = "piercings"
@@ -226,7 +232,7 @@ func Test_PerformerStore_Update(t *testing.T) {
ID: performerIDs[performerIdxWithGallery],
Name: name,
Disambiguation: disambiguation,
Gender: gender,
Gender: &gender,
URL: url,
Twitter: twitter,
Instagram: instagram,
@@ -237,6 +243,8 @@ func Test_PerformerStore_Update(t *testing.T) {
Height: &height,
Measurements: measurements,
FakeTits: fakeTits,
PenisLength: &penisLength,
Circumcised: &circumcised,
CareerLength: careerLength,
Tattoos: tattoos,
Piercings: piercings,
@@ -327,6 +335,7 @@ func clearPerformerPartial() models.PerformerPartial {
nullString := models.OptionalString{Set: true, Null: true}
nullDate := models.OptionalDate{Set: true, Null: true}
nullInt := models.OptionalInt{Set: true, Null: true}
nullFloat := models.OptionalFloat64{Set: true, Null: true}
// leave mandatory fields
return models.PerformerPartial{
@@ -342,6 +351,8 @@ func clearPerformerPartial() models.PerformerPartial {
Height: nullInt,
Measurements: nullString,
FakeTits: nullString,
PenisLength: nullFloat,
Circumcised: nullString,
CareerLength: nullString,
Tattoos: nullString,
Piercings: nullString,
@@ -372,6 +383,8 @@ func Test_PerformerStore_UpdatePartial(t *testing.T) {
height = 143
measurements = "measurements"
fakeTits = "fakeTits"
penisLength = 1.23
circumcised = models.CircumisedEnumCut
careerLength = "careerLength"
tattoos = "tattoos"
piercings = "piercings"
@@ -415,6 +428,8 @@ func Test_PerformerStore_UpdatePartial(t *testing.T) {
Height: models.NewOptionalInt(height),
Measurements: models.NewOptionalString(measurements),
FakeTits: models.NewOptionalString(fakeTits),
PenisLength: models.NewOptionalFloat64(penisLength),
Circumcised: models.NewOptionalString(circumcised.String()),
CareerLength: models.NewOptionalString(careerLength),
Tattoos: models.NewOptionalString(tattoos),
Piercings: models.NewOptionalString(piercings),
@@ -453,7 +468,7 @@ func Test_PerformerStore_UpdatePartial(t *testing.T) {
ID: performerIDs[performerIdxWithDupName],
Name: name,
Disambiguation: disambiguation,
Gender: gender,
Gender: &gender,
URL: url,
Twitter: twitter,
Instagram: instagram,
@@ -464,6 +479,8 @@ func Test_PerformerStore_UpdatePartial(t *testing.T) {
Height: &height,
Measurements: measurements,
FakeTits: fakeTits,
PenisLength: &penisLength,
Circumcised: &circumcised,
CareerLength: careerLength,
Tattoos: tattoos,
Piercings: piercings,
@@ -957,16 +974,30 @@ func TestPerformerQuery(t *testing.T) {
false,
},
{
"alias",
"circumcised (cut)",
nil,
&models.PerformerFilterType{
Aliases: &models.StringCriterionInput{
Value: getPerformerStringValue(performerIdxWithGallery, "alias"),
Modifier: models.CriterionModifierEquals,
Circumcised: &models.CircumcisionCriterionInput{
Value: []models.CircumisedEnum{models.CircumisedEnumCut},
Modifier: models.CriterionModifierIncludes,
},
},
[]int{performerIdxWithGallery},
[]int{performerIdxWithScene},
[]int{performerIdx1WithScene},
[]int{performerIdxWithScene, performerIdx2WithScene},
false,
},
{
"circumcised (excludes cut)",
nil,
&models.PerformerFilterType{
Circumcised: &models.CircumcisionCriterionInput{
Value: []models.CircumisedEnum{models.CircumisedEnumCut},
Modifier: models.CriterionModifierExcludes,
},
},
[]int{performerIdx2WithScene},
// performerIdxWithScene has null value
[]int{performerIdx1WithScene, performerIdxWithScene},
false,
},
}
@@ -995,6 +1026,107 @@ func TestPerformerQuery(t *testing.T) {
}
}
func TestPerformerQueryPenisLength(t *testing.T) {
var upper = 4.0
tests := []struct {
name string
modifier models.CriterionModifier
value float64
value2 *float64
}{
{
"equals",
models.CriterionModifierEquals,
1,
nil,
},
{
"not equals",
models.CriterionModifierNotEquals,
1,
nil,
},
{
"greater than",
models.CriterionModifierGreaterThan,
1,
nil,
},
{
"between",
models.CriterionModifierBetween,
2,
&upper,
},
{
"greater than",
models.CriterionModifierNotBetween,
2,
&upper,
},
{
"null",
models.CriterionModifierIsNull,
0,
nil,
},
{
"not null",
models.CriterionModifierNotNull,
0,
nil,
},
}
for _, tt := range tests {
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
filter := &models.PerformerFilterType{
PenisLength: &models.FloatCriterionInput{
Modifier: tt.modifier,
Value: tt.value,
Value2: tt.value2,
},
}
performers, _, err := db.Performer.Query(ctx, filter, nil)
if err != nil {
t.Errorf("PerformerStore.Query() error = %v", err)
return
}
for _, p := range performers {
verifyFloat(t, p.PenisLength, *filter.PenisLength)
}
})
}
}
func verifyFloat(t *testing.T, value *float64, criterion models.FloatCriterionInput) bool {
t.Helper()
assert := assert.New(t)
switch criterion.Modifier {
case models.CriterionModifierEquals:
return assert.NotNil(value) && assert.Equal(criterion.Value, *value)
case models.CriterionModifierNotEquals:
return assert.NotNil(value) && assert.NotEqual(criterion.Value, *value)
case models.CriterionModifierGreaterThan:
return assert.NotNil(value) && assert.Greater(*value, criterion.Value)
case models.CriterionModifierLessThan:
return assert.NotNil(value) && assert.Less(*value, criterion.Value)
case models.CriterionModifierBetween:
return assert.NotNil(value) && assert.GreaterOrEqual(*value, criterion.Value) && assert.LessOrEqual(*value, *criterion.Value2)
case models.CriterionModifierNotBetween:
return assert.NotNil(value) && assert.True(*value < criterion.Value || *value > *criterion.Value2)
case models.CriterionModifierIsNull:
return assert.Nil(value)
case models.CriterionModifierNotNull:
return assert.NotNil(value)
}
return false
}
func TestPerformerQueryForAutoTag(t *testing.T) {
withTxn(func(ctx context.Context) error {
tqb := db.Performer