mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-12-01 02:33:33 -06:00
[feature] Hashtag federation (in/out), hashtag client API endpoints (#2032)
* update go-fed * do the things * remove unused columns from tags * update to latest lingo from main * further tag shenanigans * serve stub page at tag endpoint * we did it lads * tests, oh tests, ohhh tests, oh tests (doo doo doo doo) * swagger docs * document hashtag usage + federation * instanceGet * don't bother parsing tag href * rename whereStartsWith -> whereStartsLike * remove GetOrCreateTag * dont cache status tag timelineability
This commit is contained in:
parent
ed2477ebea
commit
2796a2e82f
69 changed files with 2536 additions and 482 deletions
|
|
@ -21,16 +21,14 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing"
|
||||
)
|
||||
|
||||
const (
|
||||
IDKey = "id" // IDKey is the key for media attachment IDs
|
||||
APIVersionKey = "api_version" // APIVersionKey is the key for which version of the API to use (v1 or v2)
|
||||
APIv1 = "v1" // APIV1 corresponds to version 1 of the api
|
||||
APIv2 = "v2" // APIV2 corresponds to version 2 of the api
|
||||
BasePath = "/:" + APIVersionKey + "/media" // BasePath is the base API path for making media requests through v1 or v2 of the api (for mastodon API compatibility)
|
||||
AttachmentWithID = BasePath + "/:" + IDKey // BasePathWithID corresponds to a media attachment with the given ID
|
||||
IDKey = "id" // IDKey is the key for media attachment IDs
|
||||
BasePath = "/:" + apiutil.APIVersionKey + "/media" // BasePath is the base API path for making media requests through v1 or v2 of the api (for mastodon API compatibility)
|
||||
AttachmentWithID = BasePath + "/:" + IDKey // BasePathWithID corresponds to a media attachment with the given ID
|
||||
)
|
||||
|
||||
type Module struct {
|
||||
|
|
|
|||
|
|
@ -93,10 +93,12 @@ import (
|
|||
// '500':
|
||||
// description: internal server error
|
||||
func (m *Module) MediaCreatePOSTHandler(c *gin.Context) {
|
||||
apiVersion := c.Param(APIVersionKey)
|
||||
if apiVersion != APIv1 && apiVersion != APIv2 {
|
||||
err := errors.New("api version must be one of v1 or v2 for this path")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotFound(err, err.Error()), m.processor.InstanceGetV1)
|
||||
apiVersion, errWithCode := apiutil.ParseAPIVersion(
|
||||
c.Param(apiutil.APIVersionKey),
|
||||
[]string{apiutil.APIv1, apiutil.APIv2}...,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +130,7 @@ func (m *Module) MediaCreatePOSTHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if apiVersion == APIv2 {
|
||||
if apiVersion == apiutil.APIv2 {
|
||||
// the mastodon v2 media API specifies that the URL should be null
|
||||
// and that the client should call /api/v1/media/:id to get the URL
|
||||
//
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/stretchr/testify/suite"
|
||||
mediamodule "github.com/superseriousbusiness/gotosocial/internal/api/client/media"
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/email"
|
||||
|
|
@ -169,7 +170,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateSuccessful() {
|
|||
ctx.Request = httptest.NewRequest(http.MethodPost, "http://localhost:8080/api/v1/media", bytes.NewReader(buf.Bytes())) // the endpoint we're hitting
|
||||
ctx.Request.Header.Set("Content-Type", w.FormDataContentType())
|
||||
ctx.Request.Header.Set("accept", "application/json")
|
||||
ctx.AddParam(mediamodule.APIVersionKey, mediamodule.APIv1)
|
||||
ctx.AddParam(apiutil.APIVersionKey, apiutil.APIv1)
|
||||
|
||||
// do the actual request
|
||||
suite.mediaModule.MediaCreatePOSTHandler(ctx)
|
||||
|
|
@ -254,7 +255,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateSuccessfulV2() {
|
|||
ctx.Request = httptest.NewRequest(http.MethodPost, "http://localhost:8080/api/v2/media", bytes.NewReader(buf.Bytes())) // the endpoint we're hitting
|
||||
ctx.Request.Header.Set("Content-Type", w.FormDataContentType())
|
||||
ctx.Request.Header.Set("accept", "application/json")
|
||||
ctx.AddParam(mediamodule.APIVersionKey, mediamodule.APIv2)
|
||||
ctx.AddParam(apiutil.APIVersionKey, apiutil.APIv2)
|
||||
|
||||
// do the actual request
|
||||
suite.mediaModule.MediaCreatePOSTHandler(ctx)
|
||||
|
|
@ -337,7 +338,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateLongDescription() {
|
|||
ctx.Request = httptest.NewRequest(http.MethodPost, "http://localhost:8080/api/v1/media", bytes.NewReader(buf.Bytes())) // the endpoint we're hitting
|
||||
ctx.Request.Header.Set("Content-Type", w.FormDataContentType())
|
||||
ctx.Request.Header.Set("accept", "application/json")
|
||||
ctx.AddParam(mediamodule.APIVersionKey, mediamodule.APIv1)
|
||||
ctx.AddParam(apiutil.APIVersionKey, apiutil.APIv1)
|
||||
|
||||
// do the actual request
|
||||
suite.mediaModule.MediaCreatePOSTHandler(ctx)
|
||||
|
|
@ -378,7 +379,7 @@ func (suite *MediaCreateTestSuite) TestMediaCreateTooShortDescription() {
|
|||
ctx.Request = httptest.NewRequest(http.MethodPost, "http://localhost:8080/api/v1/media", bytes.NewReader(buf.Bytes())) // the endpoint we're hitting
|
||||
ctx.Request.Header.Set("Content-Type", w.FormDataContentType())
|
||||
ctx.Request.Header.Set("accept", "application/json")
|
||||
ctx.AddParam(mediamodule.APIVersionKey, mediamodule.APIv1)
|
||||
ctx.AddParam(apiutil.APIVersionKey, apiutil.APIv1)
|
||||
|
||||
// do the actual request
|
||||
suite.mediaModule.MediaCreatePOSTHandler(ctx)
|
||||
|
|
|
|||
|
|
@ -66,9 +66,11 @@ import (
|
|||
// '500':
|
||||
// description: internal server error
|
||||
func (m *Module) MediaGETHandler(c *gin.Context) {
|
||||
if apiVersion := c.Param(APIVersionKey); apiVersion != APIv1 {
|
||||
err := errors.New("api version must be one v1 for this path")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotFound(err, err.Error()), m.processor.InstanceGetV1)
|
||||
if _, errWithCode := apiutil.ParseAPIVersion(
|
||||
c.Param(apiutil.APIVersionKey),
|
||||
[]string{apiutil.APIv1, apiutil.APIv2}...,
|
||||
); errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,9 +98,11 @@ import (
|
|||
// '500':
|
||||
// description: internal server error
|
||||
func (m *Module) MediaPUTHandler(c *gin.Context) {
|
||||
if apiVersion := c.Param(APIVersionKey); apiVersion != APIv1 {
|
||||
err := errors.New("api version must be one v1 for this path")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotFound(err, err.Error()), m.processor.InstanceGetV1)
|
||||
if _, errWithCode := apiutil.ParseAPIVersion(
|
||||
c.Param(apiutil.APIVersionKey),
|
||||
[]string{apiutil.APIv1, apiutil.APIv2}...,
|
||||
); errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import (
|
|||
"github.com/stretchr/testify/suite"
|
||||
mediamodule "github.com/superseriousbusiness/gotosocial/internal/api/client/media"
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/email"
|
||||
|
|
@ -160,7 +161,7 @@ func (suite *MediaUpdateTestSuite) TestUpdateImage() {
|
|||
ctx.Request = httptest.NewRequest(http.MethodPut, fmt.Sprintf("http://localhost:8080/api/v1/media/%s", toUpdate.ID), bytes.NewReader(buf.Bytes())) // the endpoint we're hitting
|
||||
ctx.Request.Header.Set("Content-Type", w.FormDataContentType())
|
||||
ctx.Request.Header.Set("accept", "application/json")
|
||||
ctx.AddParam(mediamodule.APIVersionKey, mediamodule.APIv1)
|
||||
ctx.AddParam(apiutil.APIVersionKey, apiutil.APIv1)
|
||||
ctx.AddParam(mediamodule.IDKey, toUpdate.ID)
|
||||
|
||||
// do the actual request
|
||||
|
|
@ -221,7 +222,7 @@ func (suite *MediaUpdateTestSuite) TestUpdateImageShortDescription() {
|
|||
ctx.Request = httptest.NewRequest(http.MethodPut, fmt.Sprintf("http://localhost:8080/api/v1/media/%s", toUpdate.ID), bytes.NewReader(buf.Bytes())) // the endpoint we're hitting
|
||||
ctx.Request.Header.Set("Content-Type", w.FormDataContentType())
|
||||
ctx.Request.Header.Set("accept", "application/json")
|
||||
ctx.AddParam(mediamodule.APIVersionKey, mediamodule.APIv1)
|
||||
ctx.AddParam(apiutil.APIVersionKey, apiutil.APIv1)
|
||||
ctx.AddParam(mediamodule.IDKey, toUpdate.ID)
|
||||
|
||||
// do the actual request
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue