2021-10-24 11:57:39 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/ *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   GoToSocial 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   Copyright  ( C )  2021  GoToSocial  Authors  admin @ gotosocial . org 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								   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  federation  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"context" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"errors" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"net/url" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-11-13 17:29:43 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/superseriousbusiness/activity/streams" 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-24 11:57:39 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"github.com/superseriousbusiness/gotosocial/internal/db" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/superseriousbusiness/gotosocial/internal/gtserror" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( p  * processor )  GetStatusReplies ( ctx  context . Context ,  requestedUsername  string ,  requestedStatusID  string ,  page  bool ,  onlyOtherAccounts  bool ,  minID  string ,  requestURL  * url . URL )  ( interface { } ,  gtserror . WithCode )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// get the account the request is referring to 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									requestedAccount ,  err  :=  p . db . GetLocalAccountByUsername ( ctx ,  requestedUsername ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  gtserror . NewErrorNotFound ( fmt . Errorf ( "database error getting account with username %s: %s" ,  requestedUsername ,  err ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// authenticate the request 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									requestingAccountURI ,  authenticated ,  err  :=  p . federator . AuthenticateFederatedRequest ( ctx ,  requestedUsername ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  ||  ! authenticated  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  gtserror . NewErrorNotAuthorized ( errors . New ( "not authorized" ) ,  "not authorized" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									requestingAccount ,  _ ,  err  :=  p . federator . GetRemoteAccount ( ctx ,  requestedUsername ,  requestingAccountURI ,  false ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  gtserror . NewErrorNotAuthorized ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// authorize the request: 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// 1. check if a block exists between the requester and the requestee 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									blocked ,  err  :=  p . db . IsBlocked ( ctx ,  requestedAccount . ID ,  requestingAccount . ID ,  true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  gtserror . NewErrorInternalError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  blocked  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  gtserror . NewErrorNotAuthorized ( fmt . Errorf ( "block exists between accounts %s and %s" ,  requestedAccount . ID ,  requestingAccount . ID ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// get the status out of the database here 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									s  :=  & gtsmodel . Status { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  p . db . GetWhere ( ctx ,  [ ] db . Where { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										{ Key :  "id" ,  Value :  requestedStatusID } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										{ Key :  "account_id" ,  Value :  requestedAccount . ID } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ,  s ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  gtserror . NewErrorNotFound ( fmt . Errorf ( "database error getting status with id %s and account id %s: %s" ,  requestedStatusID ,  requestedAccount . ID ,  err ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									visible ,  err  :=  p . filter . StatusVisible ( ctx ,  s ,  requestingAccount ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  gtserror . NewErrorInternalError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! visible  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  gtserror . NewErrorNotFound ( fmt . Errorf ( "status with id %s not visible to user with id %s" ,  s . ID ,  requestingAccount . ID ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  data  map [ string ] interface { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// now there are three scenarios: 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// 1. we're asked for the whole collection and not a page -- we can just return the collection, with no items, but a link to 'first' page. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// 2. we're asked for a page but only_other_accounts has not been set in the query -- so we should just return the first page of the collection, with no items. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// 3. we're asked for a page, and only_other_accounts has been set, and min_id has optionally been set -- so we need to return some actual items! 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-22 08:46:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									switch  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  ! page : 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-24 11:57:39 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										// scenario 1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// get the collection 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										collection ,  err  :=  p . tc . StatusToASRepliesCollection ( ctx ,  s ,  onlyOtherAccounts ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  gtserror . NewErrorInternalError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										data ,  err  =  streams . Serialize ( collection ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  gtserror . NewErrorInternalError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-22 08:46:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  page  &&  requestURL . Query ( ) . Get ( "only_other_accounts" )  ==  "" : 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-24 11:57:39 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										// scenario 2 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// get the collection 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										collection ,  err  :=  p . tc . StatusToASRepliesCollection ( ctx ,  s ,  onlyOtherAccounts ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  gtserror . NewErrorInternalError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// but only return the first page 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										data ,  err  =  streams . Serialize ( collection . GetActivityStreamsFirst ( ) . GetActivityStreamsCollectionPage ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  gtserror . NewErrorInternalError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-22 08:46:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									default : 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-24 11:57:39 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										// scenario 3 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// get immediate children 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										replies ,  err  :=  p . db . GetStatusChildren ( ctx ,  s ,  true ,  minID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  gtserror . NewErrorInternalError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// filter children and extract URIs 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										replyURIs  :=  map [ string ] * url . URL { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  r  :=  range  replies  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// only show public or unlocked statuses as replies 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  r . Visibility  !=  gtsmodel . VisibilityPublic  &&  r . Visibility  !=  gtsmodel . VisibilityUnlocked  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// respect onlyOtherAccounts parameter 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  onlyOtherAccounts  &&  r . AccountID  ==  requestedAccount . ID  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// only show replies that the status owner can see 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											visibleToStatusOwner ,  err  :=  p . filter . StatusVisible ( ctx ,  r ,  requestedAccount ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  ||  ! visibleToStatusOwner  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// only show replies that the requester can see 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											visibleToRequester ,  err  :=  p . filter . StatusVisible ( ctx ,  r ,  requestingAccount ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  ||  ! visibleToRequester  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											rURI ,  err  :=  url . Parse ( r . URI ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											replyURIs [ r . ID ]  =  rURI 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										repliesPage ,  err  :=  p . tc . StatusURIsToASRepliesPage ( ctx ,  s ,  onlyOtherAccounts ,  minID ,  replyURIs ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  gtserror . NewErrorInternalError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										data ,  err  =  streams . Serialize ( repliesPage ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  gtserror . NewErrorInternalError ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  data ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}