repliesget.go (4843B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package users 19 20 import ( 21 "encoding/json" 22 "errors" 23 "fmt" 24 "net/http" 25 "strconv" 26 "strings" 27 28 "github.com/gin-gonic/gin" 29 apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" 30 "github.com/superseriousbusiness/gotosocial/internal/gtserror" 31 ) 32 33 // StatusRepliesGETHandler swagger:operation GET /users/{username}/statuses/{status}/replies s2sRepliesGet 34 // 35 // Get the replies collection for a status. 36 // 37 // Note that the response will be a Collection with a page as `first`, as shown below, if `page` is `false`. 38 // 39 // If `page` is `true`, then the response will be a single `CollectionPage` without the wrapping `Collection`. 40 // 41 // HTTP signature is required on the request. 42 // 43 // --- 44 // tags: 45 // - s2s/federation 46 // 47 // produces: 48 // - application/activity+json 49 // 50 // parameters: 51 // - 52 // name: username 53 // type: string 54 // description: Username of the account. 55 // in: path 56 // required: true 57 // - 58 // name: status 59 // type: string 60 // description: ID of the status. 61 // in: path 62 // required: true 63 // - 64 // name: page 65 // type: boolean 66 // description: Return response as a CollectionPage. 67 // in: query 68 // default: false 69 // - 70 // name: only_other_accounts 71 // type: boolean 72 // description: Return replies only from accounts other than the status owner. 73 // in: query 74 // default: false 75 // - 76 // name: min_id 77 // type: string 78 // description: Minimum ID of the next status, used for paging. 79 // in: query 80 // 81 // responses: 82 // '200': 83 // in: body 84 // schema: 85 // "$ref": "#/definitions/swaggerCollection" 86 // '400': 87 // description: bad request 88 // '401': 89 // description: unauthorized 90 // '403': 91 // description: forbidden 92 // '404': 93 // description: not found 94 func (m *Module) StatusRepliesGETHandler(c *gin.Context) { 95 // usernames on our instance are always lowercase 96 requestedUsername := strings.ToLower(c.Param(UsernameKey)) 97 if requestedUsername == "" { 98 err := errors.New("no username specified in request") 99 apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) 100 return 101 } 102 103 // status IDs on our instance are always uppercase 104 requestedStatusID := strings.ToUpper(c.Param(StatusIDKey)) 105 if requestedStatusID == "" { 106 err := errors.New("no status id specified in request") 107 apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) 108 return 109 } 110 111 format, err := apiutil.NegotiateAccept(c, apiutil.HTMLOrActivityPubHeaders...) 112 if err != nil { 113 apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1) 114 return 115 } 116 117 if format == string(apiutil.TextHTML) { 118 // redirect to the status 119 c.Redirect(http.StatusSeeOther, "/@"+requestedUsername+"/statuses/"+requestedStatusID) 120 return 121 } 122 123 var page bool 124 if pageString := c.Query(PageKey); pageString != "" { 125 i, err := strconv.ParseBool(pageString) 126 if err != nil { 127 err := fmt.Errorf("error parsing %s: %s", PageKey, err) 128 apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) 129 return 130 } 131 page = i 132 } 133 134 onlyOtherAccounts := false 135 onlyOtherAccountsString := c.Query(OnlyOtherAccountsKey) 136 if onlyOtherAccountsString != "" { 137 i, err := strconv.ParseBool(onlyOtherAccountsString) 138 if err != nil { 139 err := fmt.Errorf("error parsing %s: %s", OnlyOtherAccountsKey, err) 140 apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) 141 return 142 } 143 onlyOtherAccounts = i 144 } 145 146 minID := "" 147 minIDString := c.Query(MinIDKey) 148 if minIDString != "" { 149 minID = minIDString 150 } 151 152 resp, errWithCode := m.processor.Fedi().StatusRepliesGet(c.Request.Context(), requestedUsername, requestedStatusID, page, onlyOtherAccounts, c.Query("only_other_accounts") != "", minID) 153 if errWithCode != nil { 154 apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) 155 return 156 } 157 158 b, err := json.Marshal(resp) 159 if err != nil { 160 apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGetV1) 161 return 162 } 163 164 c.Data(http.StatusOK, format, b) 165 }