diff options
| author | 2023-02-04 15:53:11 +0100 | |
|---|---|---|
| committer | 2023-02-04 15:53:11 +0100 | |
| commit | 80c26d61f75ca739e6071cc25b594033face3aa1 (patch) | |
| tree | f272060d7bb0aea61a284b8d22e8dea3c84d05ca /internal/api/client | |
| parent | [bugfix] Fix password change keys (#1416) (diff) | |
| download | gotosocial-80c26d61f75ca739e6071cc25b594033face3aa1.tar.xz | |
[bugfix] Allow instance thumbnail description to be set separately from image (#1417)
Diffstat (limited to 'internal/api/client')
| -rw-r--r-- | internal/api/client/instance/instancepatch.go | 14 | ||||
| -rw-r--r-- | internal/api/client/instance/instancepatch_test.go | 359 | 
2 files changed, 204 insertions, 169 deletions
diff --git a/internal/api/client/instance/instancepatch.go b/internal/api/client/instance/instancepatch.go index a71d670b9..c30b5850e 100644 --- a/internal/api/client/instance/instancepatch.go +++ b/internal/api/client/instance/instancepatch.go @@ -178,19 +178,17 @@ func validateInstanceUpdate(form *apimodel.InstanceSettingsUpdateRequest) error  		return errors.New("empty form submitted")  	} -	maxImageSize := config.GetMediaImageMaxSize() -	maxDescriptionChars := config.GetMediaDescriptionMaxChars() - -	// validate avatar if present  	if form.Avatar != nil { +		maxImageSize := config.GetMediaImageMaxSize()  		if size := form.Avatar.Size; size > int64(maxImageSize) {  			return fmt.Errorf("file size limit exceeded: limit is %d bytes but desired instance avatar was %d bytes", maxImageSize, size)  		} +	} -		if form.AvatarDescription != nil { -			if length := len([]rune(*form.AvatarDescription)); length > maxDescriptionChars { -				return fmt.Errorf("avatar description length must be less than %d characters (inclusive), but provided avatar description was %d chars", maxDescriptionChars, length) -			} +	if form.AvatarDescription != nil { +		maxDescriptionChars := config.GetMediaDescriptionMaxChars() +		if length := len([]rune(*form.AvatarDescription)); length > maxDescriptionChars { +			return fmt.Errorf("avatar description length must be less than %d characters (inclusive), but provided avatar description was %d chars", maxDescriptionChars, length)  		}  	} diff --git a/internal/api/client/instance/instancepatch_test.go b/internal/api/client/instance/instancepatch_test.go index 0b438b823..8833014f0 100644 --- a/internal/api/client/instance/instancepatch_test.go +++ b/internal/api/client/instance/instancepatch_test.go @@ -37,37 +37,44 @@ type InstancePatchTestSuite struct {  	InstanceStandardTestSuite  } -func (suite *InstancePatchTestSuite) TestInstancePatch1() { -	requestBody, w, err := testrig.CreateMultipartFormData( -		"", "", -		map[string]string{ -			"title":            "Example Instance", -			"contact_username": "admin", -			"contact_email":    "someone@example.org", -		}) +func (suite *InstancePatchTestSuite) instancePatch(fieldName string, fileName string, extraFields map[string]string) (code int, body []byte) { +	requestBody, w, err := testrig.CreateMultipartFormData(fieldName, fileName, extraFields)  	if err != nil { -		panic(err) +		suite.FailNow(err.Error())  	} -	bodyBytes := requestBody.Bytes() -	// set up the request  	recorder := httptest.NewRecorder() -	ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPathV1, bodyBytes, w.FormDataContentType(), true) +	ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPathV1, requestBody.Bytes(), w.FormDataContentType(), true) -	// call the handler  	suite.instanceModule.InstanceUpdatePATCHHandler(ctx) -	// we should have OK because our request was valid -	suite.Equal(http.StatusOK, recorder.Code) -  	result := recorder.Result()  	defer result.Body.Close()  	b, err := io.ReadAll(result.Body) -	suite.NoError(err) +	if err != nil { +		suite.FailNow(err.Error()) +	} + +	return recorder.Code, b +} + +func (suite *InstancePatchTestSuite) TestInstancePatch1() { +	code, b := suite.instancePatch("", "", map[string]string{ +		"title":            "Example Instance", +		"contact_username": "admin", +		"contact_email":    "someone@example.org", +	}) + +	if expectedCode := http.StatusOK; code != expectedCode { +		suite.FailNowf("wrong status code", "expected %d but got %d", expectedCode, code) +	} +  	dst := new(bytes.Buffer) -	err = json.Indent(dst, b, "", "  ") -	suite.NoError(err) +	if err := json.Indent(dst, b, "", "  "); err != nil { +		suite.FailNow(err.Error()) +	} +  	suite.Equal(`{    "uri": "http://localhost:8080",    "account_domain": "localhost:8080", @@ -150,34 +157,19 @@ func (suite *InstancePatchTestSuite) TestInstancePatch1() {  }  func (suite *InstancePatchTestSuite) TestInstancePatch2() { -	requestBody, w, err := testrig.CreateMultipartFormData( -		"", "", -		map[string]string{ -			"title": "<p>Geoff's Instance</p>", -		}) -	if err != nil { -		panic(err) -	} -	bodyBytes := requestBody.Bytes() +	code, b := suite.instancePatch("", "", map[string]string{ +		"title": "<p>Geoff's Instance</p>", +	}) -	// set up the request -	recorder := httptest.NewRecorder() -	ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPathV1, bodyBytes, w.FormDataContentType(), true) - -	// call the handler -	suite.instanceModule.InstanceUpdatePATCHHandler(ctx) - -	// we should have OK because our request was valid -	suite.Equal(http.StatusOK, recorder.Code) - -	result := recorder.Result() -	defer result.Body.Close() +	if expectedCode := http.StatusOK; code != expectedCode { +		suite.FailNowf("wrong status code", "expected %d but got %d", expectedCode, code) +	} -	b, err := io.ReadAll(result.Body) -	suite.NoError(err)  	dst := new(bytes.Buffer) -	err = json.Indent(dst, b, "", "  ") -	suite.NoError(err) +	if err := json.Indent(dst, b, "", "  "); err != nil { +		suite.FailNow(err.Error()) +	} +  	suite.Equal(`{    "uri": "http://localhost:8080",    "account_domain": "localhost:8080", @@ -260,34 +252,19 @@ func (suite *InstancePatchTestSuite) TestInstancePatch2() {  }  func (suite *InstancePatchTestSuite) TestInstancePatch3() { -	requestBody, w, err := testrig.CreateMultipartFormData( -		"", "", -		map[string]string{ -			"short_description": "<p>This is some html, which is <em>allowed</em> in short descriptions.</p>", -		}) -	if err != nil { -		panic(err) -	} -	bodyBytes := requestBody.Bytes() - -	// set up the request -	recorder := httptest.NewRecorder() -	ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPathV1, bodyBytes, w.FormDataContentType(), true) - -	// call the handler -	suite.instanceModule.InstanceUpdatePATCHHandler(ctx) +	code, b := suite.instancePatch("", "", map[string]string{ +		"short_description": "<p>This is some html, which is <em>allowed</em> in short descriptions.</p>", +	}) -	// we should have OK because our request was valid -	suite.Equal(http.StatusOK, recorder.Code) - -	result := recorder.Result() -	defer result.Body.Close() +	if expectedCode := http.StatusOK; code != expectedCode { +		suite.FailNowf("wrong status code", "expected %d but got %d", expectedCode, code) +	} -	b, err := io.ReadAll(result.Body) -	suite.NoError(err)  	dst := new(bytes.Buffer) -	err = json.Indent(dst, b, "", "  ") -	suite.NoError(err) +	if err := json.Indent(dst, b, "", "  "); err != nil { +		suite.FailNow(err.Error()) +	} +  	suite.Equal(`{    "uri": "http://localhost:8080",    "account_domain": "localhost:8080", @@ -370,28 +347,18 @@ func (suite *InstancePatchTestSuite) TestInstancePatch3() {  }  func (suite *InstancePatchTestSuite) TestInstancePatch4() { -	requestBody, w, err := testrig.CreateMultipartFormData( -		"", "", -		map[string]string{}) -	if err != nil { -		panic(err) -	} -	bodyBytes := requestBody.Bytes() +	code, b := suite.instancePatch("", "", map[string]string{ +		"": "", +	}) -	// set up the request -	recorder := httptest.NewRecorder() -	ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPathV1, bodyBytes, w.FormDataContentType(), true) - -	// call the handler -	suite.instanceModule.InstanceUpdatePATCHHandler(ctx) - -	suite.Equal(http.StatusBadRequest, recorder.Code) - -	result := recorder.Result() -	defer result.Body.Close() +	if expectedCode := http.StatusBadRequest; code != expectedCode { +		suite.FailNowf("wrong status code", "expected %d but got %d", expectedCode, code) +	} -	b, err := io.ReadAll(result.Body) -	suite.NoError(err) +	dst := new(bytes.Buffer) +	if err := json.Indent(dst, b, "", "  "); err != nil { +		suite.FailNow(err.Error()) +	}  	suite.Equal(`{"error":"Bad Request: empty form submitted"}`, string(b))  } @@ -431,34 +398,19 @@ func (suite *InstancePatchTestSuite) TestInstancePatch5() {  }  func (suite *InstancePatchTestSuite) TestInstancePatch6() { -	requestBody, w, err := testrig.CreateMultipartFormData( -		"", "", -		map[string]string{ -			"contact_email": "", -		}) -	if err != nil { -		panic(err) -	} -	bodyBytes := requestBody.Bytes() +	code, b := suite.instancePatch("", "", map[string]string{ +		"contact_email": "", +	}) -	// set up the request -	recorder := httptest.NewRecorder() -	ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPathV1, bodyBytes, w.FormDataContentType(), true) - -	// call the handler -	suite.instanceModule.InstanceUpdatePATCHHandler(ctx) - -	// we should have OK because our request was valid -	suite.Equal(http.StatusOK, recorder.Code) - -	result := recorder.Result() -	defer result.Body.Close() +	if expectedCode := http.StatusOK; code != expectedCode { +		suite.FailNowf("wrong status code", "expected %d but got %d", expectedCode, code) +	} -	b, err := io.ReadAll(result.Body) -	suite.NoError(err)  	dst := new(bytes.Buffer) -	err = json.Indent(dst, b, "", "  ") -	suite.NoError(err) +	if err := json.Indent(dst, b, "", "  "); err != nil { +		suite.FailNow(err.Error()) +	} +  	suite.Equal(`{    "uri": "http://localhost:8080",    "account_domain": "localhost:8080", @@ -541,67 +493,40 @@ func (suite *InstancePatchTestSuite) TestInstancePatch6() {  }  func (suite *InstancePatchTestSuite) TestInstancePatch7() { -	requestBody, w, err := testrig.CreateMultipartFormData( -		"", "", -		map[string]string{ -			"contact_email": "not.an.email.address", -		}) -	if err != nil { -		panic(err) -	} -	bodyBytes := requestBody.Bytes() - -	// set up the request -	recorder := httptest.NewRecorder() -	ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPathV1, bodyBytes, w.FormDataContentType(), true) +	code, b := suite.instancePatch("", "", map[string]string{ +		"contact_email": "not.an.email.address", +	}) -	// call the handler -	suite.instanceModule.InstanceUpdatePATCHHandler(ctx) - -	suite.Equal(http.StatusBadRequest, recorder.Code) - -	result := recorder.Result() -	defer result.Body.Close() +	if expectedCode := http.StatusBadRequest; code != expectedCode { +		suite.FailNowf("wrong status code", "expected %d but got %d", expectedCode, code) +	} -	b, err := io.ReadAll(result.Body) -	suite.NoError(err) +	dst := new(bytes.Buffer) +	if err := json.Indent(dst, b, "", "  "); err != nil { +		suite.FailNow(err.Error()) +	}  	suite.Equal(`{"error":"Bad Request: mail: missing '@' or angle-addr"}`, string(b))  }  func (suite *InstancePatchTestSuite) TestInstancePatch8() { -	requestBody, w, err := testrig.CreateMultipartFormData( -		"thumbnail", "../../../../testrig/media/peglin.gif", -		map[string]string{ -			"thumbnail_description": "A bouncing little green peglin.", -		}) -	if err != nil { -		panic(err) -	} -	bodyBytes := requestBody.Bytes() - -	// set up the request -	recorder := httptest.NewRecorder() -	ctx := suite.newContext(recorder, http.MethodPatch, instance.InstanceInformationPathV1, bodyBytes, w.FormDataContentType(), true) +	code, b := suite.instancePatch("thumbnail", "../../../../testrig/media/peglin.gif", map[string]string{ +		"thumbnail_description": "A bouncing little green peglin."}) -	// call the handler -	suite.instanceModule.InstanceUpdatePATCHHandler(ctx) -	suite.Equal(http.StatusOK, recorder.Code) +	if expectedCode := http.StatusOK; code != expectedCode { +		suite.FailNowf("wrong status code", "expected %d but got %d", expectedCode, code) +	} -	result := recorder.Result() -	defer result.Body.Close() +	dst := new(bytes.Buffer) +	if err := json.Indent(dst, b, "", "  "); err != nil { +		suite.FailNow(err.Error()) +	}  	instanceAccount, err := suite.db.GetInstanceAccount(context.Background(), "")  	if err != nil {  		suite.FailNow(err.Error())  	} -	suite.NotEmpty(instanceAccount.AvatarMediaAttachmentID) -	b, err := io.ReadAll(result.Body) -	suite.NoError(err) -	dst := new(bytes.Buffer) -	err = json.Indent(dst, b, "", "  ") -	suite.NoError(err)  	suite.Equal(`{    "uri": "http://localhost:8080",    "account_domain": "localhost:8080", @@ -685,7 +610,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch8() {  }`, dst.String())  	// extra bonus: check the v2 model thumbnail after the patch -	instanceV2, err := suite.processor.InstanceGetV2(ctx) +	instanceV2, err := suite.processor.InstanceGetV2(context.Background())  	if err != nil {  		suite.FailNow(err.Error())  	} @@ -701,6 +626,118 @@ func (suite *InstancePatchTestSuite) TestInstancePatch8() {    "thumbnail_description": "A bouncing little green peglin.",    "blurhash": "LG9t;qRS4YtO.4WDRlt5IXoxtPj["  }`, string(instanceV2ThumbnailJson)) + +	// double extra special bonus: now update the image description without changing the image +	code2, b2 := suite.instancePatch("", "", map[string]string{ +		"thumbnail_description": "updating the thumbnail description without changing anything else!", +	}) + +	if expectedCode := http.StatusOK; code2 != expectedCode { +		suite.FailNowf("wrong status code", "expected %d but got %d", expectedCode, code2) +	} + +	// just extract the value we wanna check, no need to print the whole thing again +	i := make(map[string]interface{}) +	if err := json.Unmarshal(b2, &i); err != nil { +		suite.FailNow(err.Error()) +	} + +	suite.EqualValues("updating the thumbnail description without changing anything else!", i["thumbnail_description"]) +} + +func (suite *InstancePatchTestSuite) TestInstancePatch9() { +	code, b := suite.instancePatch("", "", map[string]string{ +		"thumbnail_description": "setting a new description without having a custom image set; this should change nothing!", +	}) + +	if expectedCode := http.StatusOK; code != expectedCode { +		suite.FailNowf("wrong status code", "expected %d but got %d", expectedCode, code) +	} + +	dst := new(bytes.Buffer) +	if err := json.Indent(dst, b, "", "  "); err != nil { +		suite.FailNow(err.Error()) +	} + +	suite.Equal(`{ +  "uri": "http://localhost:8080", +  "account_domain": "localhost:8080", +  "title": "GoToSocial Testrig Instance", +  "description": "\u003cp\u003eThis is the GoToSocial testrig. It doesn't federate or anything.\u003c/p\u003e\u003cp\u003eWhen the testrig is shut down, all data on it will be deleted.\u003c/p\u003e\u003cp\u003eDon't use this in production!\u003c/p\u003e", +  "short_description": "\u003cp\u003eThis is the GoToSocial testrig. It doesn't federate or anything.\u003c/p\u003e\u003cp\u003eWhen the testrig is shut down, all data on it will be deleted.\u003c/p\u003e\u003cp\u003eDon't use this in production!\u003c/p\u003e", +  "email": "admin@example.org", +  "version": "0.0.0-testrig", +  "registrations": true, +  "approval_required": true, +  "invites_enabled": false, +  "configuration": { +    "statuses": { +      "max_characters": 5000, +      "max_media_attachments": 6, +      "characters_reserved_per_url": 25 +    }, +    "media_attachments": { +      "supported_mime_types": [ +        "image/jpeg", +        "image/gif", +        "image/png", +        "image/webp", +        "video/mp4" +      ], +      "image_size_limit": 10485760, +      "image_matrix_limit": 16777216, +      "video_size_limit": 41943040, +      "video_frame_rate_limit": 60, +      "video_matrix_limit": 16777216 +    }, +    "polls": { +      "max_options": 6, +      "max_characters_per_option": 50, +      "min_expiration": 300, +      "max_expiration": 2629746 +    }, +    "accounts": { +      "allow_custom_css": true, +      "max_featured_tags": 10 +    }, +    "emojis": { +      "emoji_size_limit": 51200 +    } +  }, +  "urls": { +    "streaming_api": "wss://localhost:8080" +  }, +  "stats": { +    "domain_count": 2, +    "status_count": 16, +    "user_count": 4 +  }, +  "thumbnail": "http://localhost:8080/assets/logo.png", +  "contact_account": { +    "id": "01F8MH17FWEB39HZJ76B6VXSKF", +    "username": "admin", +    "acct": "admin", +    "display_name": "", +    "locked": false, +    "bot": false, +    "created_at": "2022-05-17T13:10:59.000Z", +    "note": "", +    "url": "http://localhost:8080/@admin", +    "avatar": "", +    "avatar_static": "", +    "header": "http://localhost:8080/assets/default_header.png", +    "header_static": "http://localhost:8080/assets/default_header.png", +    "followers_count": 1, +    "following_count": 1, +    "statuses_count": 4, +    "last_status_at": "2021-10-20T10:41:37.000Z", +    "emojis": [], +    "fields": [], +    "enable_rss": true, +    "role": "admin" +  }, +  "max_toot_chars": 5000 +}`, dst.String())  }  func TestInstancePatchTestSuite(t *testing.T) {  | 
