| 
									
										
										
										
											2021-05-27 16:06:24 +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 federatingdb | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/go-fed/activity/streams/vocab" | 
					
						
							|  |  |  | 	"github.com/sirupsen/logrus" | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/db" | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/id" | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/messages" | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Create adds a new entry to the database which must be able to be | 
					
						
							|  |  |  | // keyed by its id. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Note that Activity values received from federated peers may also be | 
					
						
							|  |  |  | // created in the database this way if the Federating Protocol is | 
					
						
							|  |  |  | // enabled. The client may freely decide to store only the id instead of | 
					
						
							|  |  |  | // the entire value. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The library makes this call only after acquiring a lock first. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Under certain conditions and network activities, Create may be called | 
					
						
							|  |  |  | // multiple times for the same ActivityStreams object. | 
					
						
							|  |  |  | func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error { | 
					
						
							|  |  |  | 	l := f.log.WithFields( | 
					
						
							|  |  |  | 		logrus.Fields{ | 
					
						
							| 
									
										
										
										
											2021-10-04 15:24:19 +02:00
										 |  |  | 			"func": "Create", | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-10-04 15:24:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if l.Level >= logrus.DebugLevel { | 
					
						
							|  |  |  | 		i, err := marshalItem(asType) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		l = l.WithField("create", i) | 
					
						
							|  |  |  | 		l.Debug("entering Create") | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-04 15:24:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	targetAcct, fromFederatorChan, err := extractFromCtx(ctx) | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-04 15:24:19 +02:00
										 |  |  | 	if targetAcct == nil || fromFederatorChan == nil { | 
					
						
							|  |  |  | 		// If the target account or federator channel wasn't set on the context, that means this request didn't pass | 
					
						
							|  |  |  | 		// through the API, but came from inside GtS as the result of another activity on this instance. That being so, | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 		// we can safely just ignore this activity, since we know we've already processed it elsewhere. | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch asType.GetTypeName() { | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	case ap.ActivityCreate: | 
					
						
							| 
									
										
										
										
											2021-06-17 18:02:33 +02:00
										 |  |  | 		// CREATE SOMETHING | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		create, ok := asType.(vocab.ActivityStreamsCreate) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 			return errors.New("CREATE: could not convert type to create") | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		object := create.GetActivityStreamsObject() | 
					
						
							|  |  |  | 		for objectIter := object.Begin(); objectIter != object.End(); objectIter = objectIter.Next() { | 
					
						
							|  |  |  | 			switch objectIter.GetType().GetTypeName() { | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 			case ap.ObjectNote: | 
					
						
							| 
									
										
										
										
											2021-06-17 18:02:33 +02:00
										 |  |  | 				// CREATE A NOTE | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 				note := objectIter.GetActivityStreamsNote() | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 				status, err := f.typeConverter.ASStatusToStatus(ctx, note) | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 				if err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 					return fmt.Errorf("CREATE: error converting note to status: %s", err) | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// id the status based on the time it was created | 
					
						
							|  |  |  | 				statusID, err := id.NewULIDFromTime(status.CreatedAt) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					return err | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				status.ID = statusID | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 				if err := f.db.PutStatus(ctx, status); err != nil { | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 					if err == db.ErrAlreadyExists { | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 						// the status already exists in the database, which means we've already handled everything else, | 
					
						
							|  |  |  | 						// so we can just return nil here and be done with it. | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 						return nil | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 					// an actual error has happened | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 					return fmt.Errorf("CREATE: database error inserting status: %s", err) | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 				fromFederatorChan <- messages.FromFederator{ | 
					
						
							|  |  |  | 					APObjectType:     ap.ObjectNote, | 
					
						
							|  |  |  | 					APActivityType:   ap.ActivityCreate, | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 					GTSModel:         status, | 
					
						
							|  |  |  | 					ReceivingAccount: targetAcct, | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	case ap.ActivityFollow: | 
					
						
							| 
									
										
										
										
											2021-07-11 16:22:21 +02:00
										 |  |  | 		// FOLLOW SOMETHING | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		follow, ok := asType.(vocab.ActivityStreamsFollow) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 			return errors.New("CREATE: could not convert type to follow") | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 		followRequest, err := f.typeConverter.ASFollowToFollowRequest(ctx, follow) | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 			return fmt.Errorf("CREATE: could not convert Follow to follow request: %s", err) | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 		newID, err := id.NewULID() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		followRequest.ID = newID | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 		if err := f.db.Put(ctx, followRequest); err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 			return fmt.Errorf("CREATE: database error inserting follow request: %s", err) | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 		fromFederatorChan <- messages.FromFederator{ | 
					
						
							|  |  |  | 			APObjectType:     ap.ActivityFollow, | 
					
						
							|  |  |  | 			APActivityType:   ap.ActivityCreate, | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 			GTSModel:         followRequest, | 
					
						
							|  |  |  | 			ReceivingAccount: targetAcct, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	case ap.ActivityLike: | 
					
						
							| 
									
										
										
										
											2021-07-11 16:22:21 +02:00
										 |  |  | 		// LIKE SOMETHING | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		like, ok := asType.(vocab.ActivityStreamsLike) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 			return errors.New("CREATE: could not convert type to like") | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 		fave, err := f.typeConverter.ASLikeToFave(ctx, like) | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 			return fmt.Errorf("CREATE: could not convert Like to fave: %s", err) | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 		newID, err := id.NewULID() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fave.ID = newID | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 		if err := f.db.Put(ctx, fave); err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 			return fmt.Errorf("CREATE: database error inserting fave: %s", err) | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 		fromFederatorChan <- messages.FromFederator{ | 
					
						
							|  |  |  | 			APObjectType:     ap.ActivityLike, | 
					
						
							|  |  |  | 			APActivityType:   ap.ActivityCreate, | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 			GTSModel:         fave, | 
					
						
							|  |  |  | 			ReceivingAccount: targetAcct, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 	case ap.ActivityBlock: | 
					
						
							| 
									
										
										
										
											2021-07-11 16:22:21 +02:00
										 |  |  | 		// BLOCK SOMETHING | 
					
						
							|  |  |  | 		blockable, ok := asType.(vocab.ActivityStreamsBlock) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 			return errors.New("CREATE: could not convert type to block") | 
					
						
							| 
									
										
										
										
											2021-07-11 16:22:21 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 		block, err := f.typeConverter.ASBlockToBlock(ctx, blockable) | 
					
						
							| 
									
										
										
										
											2021-07-11 16:22:21 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 			return fmt.Errorf("CREATE: could not convert Block to gts model block") | 
					
						
							| 
									
										
										
										
											2021-07-11 16:22:21 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		newID, err := id.NewULID() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		block.ID = newID | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 		if err := f.db.Put(ctx, block); err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-27 10:45:22 +02:00
										 |  |  | 			return fmt.Errorf("CREATE: database error inserting block: %s", err) | 
					
						
							| 
									
										
										
										
											2021-07-11 16:22:21 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-31 15:59:12 +02:00
										 |  |  | 		fromFederatorChan <- messages.FromFederator{ | 
					
						
							|  |  |  | 			APObjectType:     ap.ActivityBlock, | 
					
						
							|  |  |  | 			APActivityType:   ap.ActivityCreate, | 
					
						
							| 
									
										
										
										
											2021-07-11 16:22:21 +02:00
										 |  |  | 			GTSModel:         block, | 
					
						
							|  |  |  | 			ReceivingAccount: targetAcct, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-27 16:06:24 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |