mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-21 16:55:38 +03:00
[bugfix] Fix setting immediate expires_at
value on filter endpoints (#3513)
* [bugfix] Fix setting immediate `expires_at` value on filter endpoints * update wording * update wording * oh my
This commit is contained in:
parent
53aaeb18d4
commit
e953d80dff
6 changed files with 138 additions and 98 deletions
|
@ -19,9 +19,7 @@ package accounts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
|
@ -140,25 +138,15 @@ func normalizeCreateUpdateMute(form *apimodel.UserMuteCreateUpdateRequest) error
|
||||||
// Apply defaults for missing fields.
|
// Apply defaults for missing fields.
|
||||||
form.Notifications = util.Ptr(util.PtrOrValue(form.Notifications, false))
|
form.Notifications = util.Ptr(util.PtrOrValue(form.Notifications, false))
|
||||||
|
|
||||||
// Normalize mute duration if necessary.
|
// Normalize duration if necessary.
|
||||||
// If we parsed this as JSON, expires_in
|
if form.DurationI != nil {
|
||||||
// may be either a float64 or a string.
|
// If we parsed this as JSON, duration
|
||||||
if ei := form.DurationI; ei != nil {
|
// may be either a float64 or a string.
|
||||||
switch e := ei.(type) {
|
duration, err := apiutil.ParseDuration(form.DurationI, "duration")
|
||||||
case float64:
|
if err != nil {
|
||||||
form.Duration = util.Ptr(int(e))
|
return err
|
||||||
|
|
||||||
case string:
|
|
||||||
duration, err := strconv.Atoi(e)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not parse duration value %s as integer: %w", e, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
form.Duration = &duration
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("could not parse expires_in type %T as integer", ei)
|
|
||||||
}
|
}
|
||||||
|
form.Duration = duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpret zero as indefinite duration.
|
// Interpret zero as indefinite duration.
|
||||||
|
|
|
@ -19,15 +19,14 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/api/model"
|
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
|
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/validate"
|
"github.com/superseriousbusiness/gotosocial/internal/validate"
|
||||||
)
|
)
|
||||||
|
|
||||||
func validateNormalizeCreateUpdateFilter(form *model.FilterCreateUpdateRequestV1) error {
|
func validateNormalizeCreateUpdateFilter(form *apimodel.FilterCreateUpdateRequestV1) error {
|
||||||
if err := validate.FilterKeyword(form.Phrase); err != nil {
|
if err := validate.FilterKeyword(form.Phrase); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -48,25 +47,23 @@ func validateNormalizeCreateUpdateFilter(form *model.FilterCreateUpdateRequestV1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize filter expiry if necessary.
|
// Normalize filter expiry if necessary.
|
||||||
// If we parsed this as JSON, expires_in
|
if form.ExpiresInI != nil {
|
||||||
// may be either a float64 or a string.
|
// If we parsed this as JSON, expires_in
|
||||||
if ei := form.ExpiresInI; ei != nil {
|
// may be either a float64 or a string.
|
||||||
switch e := ei.(type) {
|
var err error
|
||||||
case float64:
|
form.ExpiresIn, err = apiutil.ParseDuration(
|
||||||
form.ExpiresIn = util.Ptr(int(e))
|
form.ExpiresInI,
|
||||||
|
"expires_in",
|
||||||
case string:
|
)
|
||||||
expiresIn, err := strconv.Atoi(e)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return fmt.Errorf("could not parse expires_in value %s as integer: %w", e, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
form.ExpiresIn = &expiresIn
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("could not parse expires_in type %T as integer", ei)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interpret zero as indefinite duration.
|
||||||
|
if form.ExpiresIn != nil && *form.ExpiresIn == 0 {
|
||||||
|
form.ExpiresIn = nil
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,7 @@
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
|
@ -228,26 +226,24 @@ func validateNormalizeCreateFilter(form *apimodel.FilterCreateRequestV2) error {
|
||||||
form.FilterAction = util.Ptr(action)
|
form.FilterAction = util.Ptr(action)
|
||||||
|
|
||||||
// Normalize filter expiry if necessary.
|
// Normalize filter expiry if necessary.
|
||||||
// If we parsed this as JSON, expires_in
|
if form.ExpiresInI != nil {
|
||||||
// may be either a float64 or a string.
|
// If we parsed this as JSON, expires_in
|
||||||
if ei := form.ExpiresInI; ei != nil {
|
// may be either a float64 or a string.
|
||||||
switch e := ei.(type) {
|
var err error
|
||||||
case float64:
|
form.ExpiresIn, err = apiutil.ParseDuration(
|
||||||
form.ExpiresIn = util.Ptr(int(e))
|
form.ExpiresInI,
|
||||||
|
"expires_in",
|
||||||
case string:
|
)
|
||||||
expiresIn, err := strconv.Atoi(e)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return fmt.Errorf("could not parse expires_in value %s as integer: %w", e, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
form.ExpiresIn = &expiresIn
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("could not parse expires_in type %T as integer", ei)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interpret zero as indefinite duration.
|
||||||
|
if form.ExpiresIn != nil && *form.ExpiresIn == 0 {
|
||||||
|
form.ExpiresIn = nil
|
||||||
|
}
|
||||||
|
|
||||||
// Normalize and validate new keywords and statuses.
|
// Normalize and validate new keywords and statuses.
|
||||||
for i, formKeyword := range form.Keywords {
|
for i, formKeyword := range form.Keywords {
|
||||||
if err := validate.FilterKeyword(formKeyword.Keyword); err != nil {
|
if err := validate.FilterKeyword(formKeyword.Keyword); err != nil {
|
||||||
|
|
|
@ -19,9 +19,7 @@ package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
|
@ -272,26 +270,24 @@ func validateNormalizeUpdateFilter(form *apimodel.FilterUpdateRequestV2) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize filter expiry if necessary.
|
// Normalize filter expiry if necessary.
|
||||||
// If we parsed this as JSON, expires_in
|
if form.ExpiresInI != nil {
|
||||||
// may be either a float64 or a string.
|
// If we parsed this as JSON, expires_in
|
||||||
if ei := form.ExpiresInI; ei != nil {
|
// may be either a float64 or a string.
|
||||||
switch e := ei.(type) {
|
var err error
|
||||||
case float64:
|
form.ExpiresIn, err = apiutil.ParseDuration(
|
||||||
form.ExpiresIn = util.Ptr(int(e))
|
form.ExpiresInI,
|
||||||
|
"expires_in",
|
||||||
case string:
|
)
|
||||||
expiresIn, err := strconv.Atoi(e)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return fmt.Errorf("could not parse expires_in value %s as integer: %w", e, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
form.ExpiresIn = &expiresIn
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("could not parse expires_in type %T as integer", ei)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interpret zero as indefinite duration.
|
||||||
|
if form.ExpiresIn != nil && *form.ExpiresIn == 0 {
|
||||||
|
form.ExpiresIn = nil
|
||||||
|
}
|
||||||
|
|
||||||
// Normalize and validate updates.
|
// Normalize and validate updates.
|
||||||
for i, formKeyword := range form.Keywords {
|
for i, formKeyword := range form.Keywords {
|
||||||
if formKeyword.Keyword != nil {
|
if formKeyword.Keyword != nil {
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
@ -474,25 +473,19 @@ func validateStatusPoll(form *apimodel.StatusCreateRequest) gtserror.WithCode {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize poll expiry if necessary.
|
// Normalize poll expiry if necessary.
|
||||||
// If we parsed this as JSON, expires_in
|
if form.Poll.ExpiresInI != nil {
|
||||||
// may be either a float64 or a string.
|
// If we parsed this as JSON, expires_in
|
||||||
if ei := form.Poll.ExpiresInI; ei != nil {
|
// may be either a float64 or a string.
|
||||||
switch e := ei.(type) {
|
expiresIn, err := apiutil.ParseDuration(
|
||||||
case float64:
|
form.Poll.ExpiresInI,
|
||||||
form.Poll.ExpiresIn = int(e)
|
"expires_in",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return gtserror.NewErrorBadRequest(err, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
case string:
|
if expiresIn != nil {
|
||||||
expiresIn, err := strconv.Atoi(e)
|
form.Poll.ExpiresIn = *expiresIn
|
||||||
if err != nil {
|
|
||||||
text := fmt.Sprintf("could not parse expires_in value %s as integer: %v", e, err)
|
|
||||||
return gtserror.NewErrorBadRequest(errors.New(text), text)
|
|
||||||
}
|
|
||||||
|
|
||||||
form.Poll.ExpiresIn = expiresIn
|
|
||||||
|
|
||||||
default:
|
|
||||||
text := fmt.Sprintf("could not parse expires_in type %T as integer", ei)
|
|
||||||
return gtserror.NewErrorBadRequest(errors.New(text), text)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
70
internal/api/util/parseform.go
Normal file
70
internal/api/util/parseform.go
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// GoToSocial
|
||||||
|
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseDuration parses the given raw interface belonging to
|
||||||
|
// the given fieldName as an integer duration.
|
||||||
|
//
|
||||||
|
// Will return nil, nil if rawI is the zero value of its type.
|
||||||
|
func ParseDuration(rawI any, fieldName string) (*int, error) {
|
||||||
|
var (
|
||||||
|
asInteger int
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
switch raw := rawI.(type) {
|
||||||
|
case float64:
|
||||||
|
// Submitted as JSON number
|
||||||
|
// (casts to float64 by default).
|
||||||
|
asInteger = int(raw)
|
||||||
|
|
||||||
|
case string:
|
||||||
|
// Submitted as JSON string or form field.
|
||||||
|
asInteger, err = strconv.Atoi(raw)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"could not parse %s value %s as integer: %w",
|
||||||
|
fieldName, raw, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Submitted as god-knows-what.
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"could not parse %s type %T as integer",
|
||||||
|
fieldName, rawI,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Someone submitted 0,
|
||||||
|
// don't point to this.
|
||||||
|
if asInteger == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &asInteger, nil
|
||||||
|
}
|
Loading…
Reference in a new issue