diff options
Diffstat (limited to 'internal')
69 files changed, 981 insertions, 553 deletions
| diff --git a/internal/ap/activitystreams.go b/internal/ap/activitystreams.go new file mode 100644 index 000000000..e00bf3f1c --- /dev/null +++ b/internal/ap/activitystreams.go @@ -0,0 +1,72 @@ +/* +   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 ap + +// https://www.w3.org/TR/activitystreams-vocabulary +const ( +	ActivityAccept          = "Accept"          // ActivityStreamsAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept +	ActivityAdd             = "Add"             // ActivityStreamsAdd https://www.w3.org/TR/activitystreams-vocabulary/#dfn-add +	ActivityAnnounce        = "Announce"        // ActivityStreamsAnnounce https://www.w3.org/TR/activitystreams-vocabulary/#dfn-announce +	ActivityArrive          = "Arrive"          // ActivityStreamsArrive https://www.w3.org/TR/activitystreams-vocabulary/#dfn-arrive +	ActivityBlock           = "Block"           // ActivityStreamsBlock https://www.w3.org/TR/activitystreams-vocabulary/#dfn-block +	ActivityCreate          = "Create"          // ActivityStreamsCreate https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create +	ActivityDelete          = "Delete"          // ActivityStreamsDelete https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete +	ActivityDislike         = "Dislike"         // ActivityStreamsDislike https://www.w3.org/TR/activitystreams-vocabulary/#dfn-dislike +	ActivityFlag            = "Flag"            // ActivityStreamsFlag https://www.w3.org/TR/activitystreams-vocabulary/#dfn-flag +	ActivityFollow          = "Follow"          // ActivityStreamsFollow https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow +	ActivityIgnore          = "Ignore"          // ActivityStreamsIgnore https://www.w3.org/TR/activitystreams-vocabulary/#dfn-ignore +	ActivityInvite          = "Invite"          // ActivityStreamsInvite https://www.w3.org/TR/activitystreams-vocabulary/#dfn-invite +	ActivityJoin            = "Join"            // ActivityStreamsJoin https://www.w3.org/TR/activitystreams-vocabulary/#dfn-join +	ActivityLeave           = "Leave"           // ActivityStreamsLeave https://www.w3.org/TR/activitystreams-vocabulary/#dfn-leave +	ActivityLike            = "Like"            // ActivityStreamsLike https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like +	ActivityListen          = "Listen"          // ActivityStreamsListen https://www.w3.org/TR/activitystreams-vocabulary/#dfn-listen +	ActivityMove            = "Move"            // ActivityStreamsMove https://www.w3.org/TR/activitystreams-vocabulary/#dfn-move +	ActivityOffer           = "Offer"           // ActivityStreamsOffer https://www.w3.org/TR/activitystreams-vocabulary/#dfn-offer +	ActivityQuestion        = "Question"        // ActivityStreamsQuestion https://www.w3.org/TR/activitystreams-vocabulary/#dfn-question +	ActivityReject          = "Reject"          // ActivityStreamsReject https://www.w3.org/TR/activitystreams-vocabulary/#dfn-reject +	ActivityRead            = "Read"            // ActivityStreamsRead https://www.w3.org/TR/activitystreams-vocabulary/#dfn-read +	ActivityRemove          = "Remove"          // ActivityStreamsRemove https://www.w3.org/TR/activitystreams-vocabulary/#dfn-remove +	ActivityTentativeReject = "TentativeReject" // ActivityStreamsTentativeReject https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tentativereject +	ActivityTentativeAccept = "TentativeAccept" // ActivityStreamsTentativeAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tentativeaccept +	ActivityTravel          = "Travel"          // ActivityStreamsTravel https://www.w3.org/TR/activitystreams-vocabulary/#dfn-travel +	ActivityUndo            = "Undo"            // ActivityStreamsUndo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-undo +	ActivityUpdate          = "Update"          // ActivityStreamsUpdate https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update +	ActivityView            = "View"            // ActivityStreamsView https://www.w3.org/TR/activitystreams-vocabulary/#dfn-view + +	ActorApplication  = "Application"  // ActivityStreamsApplication https://www.w3.org/TR/activitystreams-vocabulary/#dfn-application +	ActorGroup        = "Group"        // ActivityStreamsGroup https://www.w3.org/TR/activitystreams-vocabulary/#dfn-group +	ActorOrganization = "Organization" // ActivityStreamsOrganization https://www.w3.org/TR/activitystreams-vocabulary/#dfn-organization +	ActorPerson       = "Person"       // ActivityStreamsPerson https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person +	ActorService      = "Service"      // ActivityStreamsService https://www.w3.org/TR/activitystreams-vocabulary/#dfn-service + +	ObjectArticle        = "Article"        // ActivityStreamsArticle https://www.w3.org/TR/activitystreams-vocabulary/#dfn-article +	ObjectAudio          = "Audio"          // ActivityStreamsAudio https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audio +	ObjectDocument       = "Document"       // ActivityStreamsDocument https://www.w3.org/TR/activitystreams-vocabulary/#dfn-document +	ObjectEvent          = "Event"          // ActivityStreamsEvent https://www.w3.org/TR/activitystreams-vocabulary/#dfn-event +	ObjectImage          = "Image"          // ActivityStreamsImage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image +	ObjectNote           = "Note"           // ActivityStreamsNote https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note +	ObjectPage           = "Page"           // ActivityStreamsPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-page +	ObjectPlace          = "Place"          // ActivityStreamsPlace https://www.w3.org/TR/activitystreams-vocabulary/#dfn-place +	ObjectProfile        = "Profile"        // ActivityStreamsProfile https://www.w3.org/TR/activitystreams-vocabulary/#dfn-profile +	ObjectRelationship   = "Relationship"   // ActivityStreamsRelationship https://www.w3.org/TR/activitystreams-vocabulary/#dfn-relationship +	ObjectTombstone      = "Tombstone"      // ActivityStreamsTombstone https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone +	ObjectVideo          = "Video"          // ActivityStreamsVideo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-video +	ObjectCollection     = "Collection"     //ActivityStreamsCollection https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collection +	ObjectCollectionPage = "CollectionPage" // ActivityStreamsCollectionPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage +) diff --git a/internal/db/bundb/admin.go b/internal/db/bundb/admin.go index 6a51ffeb1..dd973ef2d 100644 --- a/internal/db/bundb/admin.go +++ b/internal/db/bundb/admin.go @@ -29,6 +29,7 @@ import (  	"strings"  	"time" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/config"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" @@ -113,7 +114,7 @@ func (a *adminDB) NewSignup(ctx context.Context, username string, reason string,  			PrivateKey:            key,  			PublicKey:             &key.PublicKey,  			PublicKeyURI:          newAccountURIs.PublicKeyURI, -			ActorType:             gtsmodel.ActivityStreamsPerson, +			ActorType:             ap.ActorPerson,  			URI:                   newAccountURIs.UserURI,  			InboxURI:              newAccountURIs.InboxURI,  			OutboxURI:             newAccountURIs.OutboxURI, @@ -207,7 +208,7 @@ func (a *adminDB) CreateInstanceAccount(ctx context.Context) db.Error {  		PrivateKey:            key,  		PublicKey:             &key.PublicKey,  		PublicKeyURI:          newAccountURIs.PublicKeyURI, -		ActorType:             gtsmodel.ActivityStreamsPerson, +		ActorType:             ap.ActorPerson,  		URI:                   newAccountURIs.UserURI,  		InboxURI:              newAccountURIs.InboxURI,  		OutboxURI:             newAccountURIs.OutboxURI, diff --git a/internal/federation/dereferencing/account.go b/internal/federation/dereferencing/account.go index 2eee0645d..8d4afa7c9 100644 --- a/internal/federation/dereferencing/account.go +++ b/internal/federation/dereferencing/account.go @@ -166,19 +166,19 @@ func (d *deref) dereferenceAccountable(ctx context.Context, username string, rem  	}  	switch t.GetTypeName() { -	case string(gtsmodel.ActivityStreamsPerson): +	case string(ap.ActorPerson):  		p, ok := t.(vocab.ActivityStreamsPerson)  		if !ok {  			return nil, errors.New("DereferenceAccountable: error resolving type as activitystreams person")  		}  		return p, nil -	case string(gtsmodel.ActivityStreamsApplication): +	case string(ap.ActorApplication):  		p, ok := t.(vocab.ActivityStreamsApplication)  		if !ok {  			return nil, errors.New("DereferenceAccountable: error resolving type as activitystreams application")  		}  		return p, nil -	case string(gtsmodel.ActivityStreamsService): +	case string(ap.ActorService):  		p, ok := t.(vocab.ActivityStreamsService)  		if !ok {  			return nil, errors.New("DereferenceAccountable: error resolving type as activitystreams service") diff --git a/internal/federation/dereferencing/collectionpage.go b/internal/federation/dereferencing/collectionpage.go index 6f0beeaf6..c5a54402c 100644 --- a/internal/federation/dereferencing/collectionpage.go +++ b/internal/federation/dereferencing/collectionpage.go @@ -28,7 +28,6 @@ import (  	"github.com/go-fed/activity/streams"  	"github.com/go-fed/activity/streams/vocab"  	"github.com/superseriousbusiness/gotosocial/internal/ap" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  )  // DereferenceCollectionPage returns the activitystreams CollectionPage at the specified IRI, or an error if something goes wrong. @@ -57,7 +56,7 @@ func (d *deref) DereferenceCollectionPage(ctx context.Context, username string,  		return nil, fmt.Errorf("DereferenceCollectionPage: error resolving json into ap vocab type: %s", err)  	} -	if t.GetTypeName() != gtsmodel.ActivityStreamsCollectionPage { +	if t.GetTypeName() != ap.ObjectCollectionPage {  		return nil, fmt.Errorf("DereferenceCollectionPage: type name %s not supported", t.GetTypeName())  	} diff --git a/internal/federation/dereferencing/status.go b/internal/federation/dereferencing/status.go index 3fa1e4133..774174e78 100644 --- a/internal/federation/dereferencing/status.go +++ b/internal/federation/dereferencing/status.go @@ -154,55 +154,55 @@ func (d *deref) dereferenceStatusable(ctx context.Context, username string, remo  	// Article, Document, Image, Video, Note, Page, Event, Place, Mention, Profile  	switch t.GetTypeName() { -	case gtsmodel.ActivityStreamsArticle: +	case ap.ObjectArticle:  		p, ok := t.(vocab.ActivityStreamsArticle)  		if !ok {  			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsArticle")  		}  		return p, nil -	case gtsmodel.ActivityStreamsDocument: +	case ap.ObjectDocument:  		p, ok := t.(vocab.ActivityStreamsDocument)  		if !ok {  			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsDocument")  		}  		return p, nil -	case gtsmodel.ActivityStreamsImage: +	case ap.ObjectImage:  		p, ok := t.(vocab.ActivityStreamsImage)  		if !ok {  			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsImage")  		}  		return p, nil -	case gtsmodel.ActivityStreamsVideo: +	case ap.ObjectVideo:  		p, ok := t.(vocab.ActivityStreamsVideo)  		if !ok {  			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsVideo")  		}  		return p, nil -	case gtsmodel.ActivityStreamsNote: +	case ap.ObjectNote:  		p, ok := t.(vocab.ActivityStreamsNote)  		if !ok {  			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsNote")  		}  		return p, nil -	case gtsmodel.ActivityStreamsPage: +	case ap.ObjectPage:  		p, ok := t.(vocab.ActivityStreamsPage)  		if !ok {  			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsPage")  		}  		return p, nil -	case gtsmodel.ActivityStreamsEvent: +	case ap.ObjectEvent:  		p, ok := t.(vocab.ActivityStreamsEvent)  		if !ok {  			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsEvent")  		}  		return p, nil -	case gtsmodel.ActivityStreamsPlace: +	case ap.ObjectPlace:  		p, ok := t.(vocab.ActivityStreamsPlace)  		if !ok {  			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsPlace")  		}  		return p, nil -	case gtsmodel.ActivityStreamsProfile: +	case ap.ObjectProfile:  		p, ok := t.(vocab.ActivityStreamsProfile)  		if !ok {  			return nil, errors.New("DereferenceStatusable: error resolving type as ActivityStreamsProfile") diff --git a/internal/federation/dereferencing/status_test.go b/internal/federation/dereferencing/status_test.go index 2d259682b..933e9f25d 100644 --- a/internal/federation/dereferencing/status_test.go +++ b/internal/federation/dereferencing/status_test.go @@ -29,6 +29,7 @@ import (  	"github.com/go-fed/activity/streams"  	"github.com/stretchr/testify/suite" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/federation/dereferencing"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" @@ -133,7 +134,7 @@ func (suite *StatusTestSuite) TestDereferenceSimpleStatus() {  	suite.False(status.Local)  	suite.Empty(status.ContentWarning)  	suite.Equal(gtsmodel.VisibilityPublic, status.Visibility) -	suite.Equal(gtsmodel.ActivityStreamsNote, status.ActivityStreamsType) +	suite.Equal(ap.ObjectNote, status.ActivityStreamsType)  	// status should be in the database  	dbStatus, err := suite.db.GetStatusByURI(context.Background(), status.URI) @@ -171,7 +172,7 @@ func (suite *StatusTestSuite) TestDereferenceStatusWithMention() {  	suite.False(status.Local)  	suite.Empty(status.ContentWarning)  	suite.Equal(gtsmodel.VisibilityPublic, status.Visibility) -	suite.Equal(gtsmodel.ActivityStreamsNote, status.ActivityStreamsType) +	suite.Equal(ap.ObjectNote, status.ActivityStreamsType)  	// status should be in the database  	dbStatus, err := suite.db.GetStatusByURI(context.Background(), status.URI) diff --git a/internal/federation/federatingdb/accept.go b/internal/federation/federatingdb/accept.go index 0b14e8a6a..ceaf4c4ef 100644 --- a/internal/federation/federatingdb/accept.go +++ b/internal/federation/federatingdb/accept.go @@ -27,8 +27,10 @@ import (  	"github.com/go-fed/activity/streams"  	"github.com/go-fed/activity/streams/vocab"  	"github.com/sirupsen/logrus" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) @@ -67,7 +69,7 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA  		l.Error("ACCEPT: from federator channel wasn't set on context")  		return nil  	} -	fromFederatorChan, ok := fromFederatorChanI.(chan gtsmodel.FromFederator) +	fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)  	if !ok {  		l.Error("ACCEPT: from federator channel was set on context but couldn't be parsed")  		return nil @@ -99,9 +101,9 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA  					return err  				} -				fromFederatorChan <- gtsmodel.FromFederator{ -					APObjectType:     gtsmodel.ActivityStreamsFollow, -					APActivityType:   gtsmodel.ActivityStreamsAccept, +				fromFederatorChan <- messages.FromFederator{ +					APObjectType:     ap.ActivityFollow, +					APActivityType:   ap.ActivityAccept,  					GTSModel:         follow,  					ReceivingAccount: targetAcct,  				} @@ -116,7 +118,7 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA  		}  		switch iter.GetType().GetTypeName() {  		// we have the whole object so we can figure out what we're accepting -		case string(gtsmodel.ActivityStreamsFollow): +		case string(ap.ActivityFollow):  			// ACCEPT FOLLOW  			asFollow, ok := iter.GetType().(vocab.ActivityStreamsFollow)  			if !ok { @@ -136,9 +138,9 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA  				return err  			} -			fromFederatorChan <- gtsmodel.FromFederator{ -				APObjectType:     gtsmodel.ActivityStreamsFollow, -				APActivityType:   gtsmodel.ActivityStreamsAccept, +			fromFederatorChan <- messages.FromFederator{ +				APObjectType:     ap.ActivityFollow, +				APActivityType:   ap.ActivityAccept,  				GTSModel:         follow,  				ReceivingAccount: targetAcct,  			} diff --git a/internal/federation/federatingdb/announce.go b/internal/federation/federatingdb/announce.go index 5cd34285e..7d7b12cbc 100644 --- a/internal/federation/federatingdb/announce.go +++ b/internal/federation/federatingdb/announce.go @@ -26,7 +26,9 @@ import (  	"github.com/go-fed/activity/streams"  	"github.com/go-fed/activity/streams/vocab"  	"github.com/sirupsen/logrus" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) @@ -65,7 +67,7 @@ func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStre  		l.Error("ANNOUNCE: from federator channel wasn't set on context")  		return nil  	} -	fromFederatorChan, ok := fromFederatorChanI.(chan gtsmodel.FromFederator) +	fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)  	if !ok {  		l.Error("ANNOUNCE: from federator channel was set on context but couldn't be parsed")  		return nil @@ -82,9 +84,9 @@ func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStre  	}  	// it's a new announce so pass it back to the processor async for dereferencing etc -	fromFederatorChan <- gtsmodel.FromFederator{ -		APObjectType:     gtsmodel.ActivityStreamsAnnounce, -		APActivityType:   gtsmodel.ActivityStreamsCreate, +	fromFederatorChan <- messages.FromFederator{ +		APObjectType:     ap.ActivityAnnounce, +		APActivityType:   ap.ActivityCreate,  		GTSModel:         boost,  		ReceivingAccount: targetAcct,  	} diff --git a/internal/federation/federatingdb/create.go b/internal/federation/federatingdb/create.go index 8ea549c5a..88b0d1e8b 100644 --- a/internal/federation/federatingdb/create.go +++ b/internal/federation/federatingdb/create.go @@ -27,9 +27,11 @@ import (  	"github.com/go-fed/activity/streams"  	"github.com/go-fed/activity/streams/vocab"  	"github.com/sirupsen/logrus" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/id" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) @@ -81,14 +83,14 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {  		l.Error("CREATE: from federator channel wasn't set on context")  		return nil  	} -	fromFederatorChan, ok := fromFederatorChanI.(chan gtsmodel.FromFederator) +	fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)  	if !ok {  		l.Error("CREATE: from federator channel was set on context but couldn't be parsed")  		return nil  	}  	switch asType.GetTypeName() { -	case gtsmodel.ActivityStreamsCreate: +	case ap.ActivityCreate:  		// CREATE SOMETHING  		create, ok := asType.(vocab.ActivityStreamsCreate)  		if !ok { @@ -97,7 +99,7 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {  		object := create.GetActivityStreamsObject()  		for objectIter := object.Begin(); objectIter != object.End(); objectIter = objectIter.Next() {  			switch objectIter.GetType().GetTypeName() { -			case gtsmodel.ActivityStreamsNote: +			case ap.ObjectNote:  				// CREATE A NOTE  				note := objectIter.GetActivityStreamsNote()  				status, err := f.typeConverter.ASStatusToStatus(ctx, note) @@ -122,15 +124,15 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {  					return fmt.Errorf("CREATE: database error inserting status: %s", err)  				} -				fromFederatorChan <- gtsmodel.FromFederator{ -					APObjectType:     gtsmodel.ActivityStreamsNote, -					APActivityType:   gtsmodel.ActivityStreamsCreate, +				fromFederatorChan <- messages.FromFederator{ +					APObjectType:     ap.ObjectNote, +					APActivityType:   ap.ActivityCreate,  					GTSModel:         status,  					ReceivingAccount: targetAcct,  				}  			}  		} -	case gtsmodel.ActivityStreamsFollow: +	case ap.ActivityFollow:  		// FOLLOW SOMETHING  		follow, ok := asType.(vocab.ActivityStreamsFollow)  		if !ok { @@ -152,13 +154,13 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {  			return fmt.Errorf("CREATE: database error inserting follow request: %s", err)  		} -		fromFederatorChan <- gtsmodel.FromFederator{ -			APObjectType:     gtsmodel.ActivityStreamsFollow, -			APActivityType:   gtsmodel.ActivityStreamsCreate, +		fromFederatorChan <- messages.FromFederator{ +			APObjectType:     ap.ActivityFollow, +			APActivityType:   ap.ActivityCreate,  			GTSModel:         followRequest,  			ReceivingAccount: targetAcct,  		} -	case gtsmodel.ActivityStreamsLike: +	case ap.ActivityLike:  		// LIKE SOMETHING  		like, ok := asType.(vocab.ActivityStreamsLike)  		if !ok { @@ -180,13 +182,13 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {  			return fmt.Errorf("CREATE: database error inserting fave: %s", err)  		} -		fromFederatorChan <- gtsmodel.FromFederator{ -			APObjectType:     gtsmodel.ActivityStreamsLike, -			APActivityType:   gtsmodel.ActivityStreamsCreate, +		fromFederatorChan <- messages.FromFederator{ +			APObjectType:     ap.ActivityLike, +			APActivityType:   ap.ActivityCreate,  			GTSModel:         fave,  			ReceivingAccount: targetAcct,  		} -	case gtsmodel.ActivityStreamsBlock: +	case ap.ActivityBlock:  		// BLOCK SOMETHING  		blockable, ok := asType.(vocab.ActivityStreamsBlock)  		if !ok { @@ -208,9 +210,9 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {  			return fmt.Errorf("CREATE: database error inserting block: %s", err)  		} -		fromFederatorChan <- gtsmodel.FromFederator{ -			APObjectType:     gtsmodel.ActivityStreamsBlock, -			APActivityType:   gtsmodel.ActivityStreamsCreate, +		fromFederatorChan <- messages.FromFederator{ +			APObjectType:     ap.ActivityBlock, +			APActivityType:   ap.ActivityCreate,  			GTSModel:         block,  			ReceivingAccount: targetAcct,  		} diff --git a/internal/federation/federatingdb/delete.go b/internal/federation/federatingdb/delete.go index 11b818168..abc3715da 100644 --- a/internal/federation/federatingdb/delete.go +++ b/internal/federation/federatingdb/delete.go @@ -24,7 +24,9 @@ import (  	"net/url"  	"github.com/sirupsen/logrus" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) @@ -61,7 +63,7 @@ func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {  		l.Error("DELETE: from federator channel wasn't set on context")  		return nil  	} -	fromFederatorChan, ok := fromFederatorChanI.(chan gtsmodel.FromFederator) +	fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)  	if !ok {  		l.Error("DELETE: from federator channel was set on context but couldn't be parsed")  		return nil @@ -76,9 +78,9 @@ func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {  		if err := f.db.DeleteByID(ctx, s.ID, >smodel.Status{}); err != nil {  			return fmt.Errorf("DELETE: err deleting status: %s", err)  		} -		fromFederatorChan <- gtsmodel.FromFederator{ -			APObjectType:     gtsmodel.ActivityStreamsNote, -			APActivityType:   gtsmodel.ActivityStreamsDelete, +		fromFederatorChan <- messages.FromFederator{ +			APObjectType:     ap.ObjectNote, +			APActivityType:   ap.ActivityDelete,  			GTSModel:         s,  			ReceivingAccount: targetAcct,  		} @@ -91,9 +93,9 @@ func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {  		if err := f.db.DeleteByID(ctx, a.ID, >smodel.Account{}); err != nil {  			return fmt.Errorf("DELETE: err deleting account: %s", err)  		} -		fromFederatorChan <- gtsmodel.FromFederator{ -			APObjectType:     gtsmodel.ActivityStreamsProfile, -			APActivityType:   gtsmodel.ActivityStreamsDelete, +		fromFederatorChan <- messages.FromFederator{ +			APObjectType:     ap.ObjectProfile, +			APActivityType:   ap.ActivityDelete,  			GTSModel:         a,  			ReceivingAccount: targetAcct,  		} diff --git a/internal/federation/federatingdb/undo.go b/internal/federation/federatingdb/undo.go index 0fa38114d..7b49815df 100644 --- a/internal/federation/federatingdb/undo.go +++ b/internal/federation/federatingdb/undo.go @@ -27,6 +27,7 @@ import (  	"github.com/go-fed/activity/streams"  	"github.com/go-fed/activity/streams/vocab"  	"github.com/sirupsen/logrus" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/util" @@ -72,7 +73,7 @@ func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo)  			continue  		}  		switch iter.GetType().GetTypeName() { -		case string(gtsmodel.ActivityStreamsFollow): +		case string(ap.ActivityFollow):  			// UNDO FOLLOW  			ASFollow, ok := iter.GetType().(vocab.ActivityStreamsFollow)  			if !ok { @@ -101,11 +102,11 @@ func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo)  			}  			l.Debug("follow undone")  			return nil -		case string(gtsmodel.ActivityStreamsLike): +		case string(ap.ActivityLike):  			// UNDO LIKE -		case string(gtsmodel.ActivityStreamsAnnounce): +		case string(ap.ActivityAnnounce):  			// UNDO BOOST/REBLOG/ANNOUNCE -		case string(gtsmodel.ActivityStreamsBlock): +		case string(ap.ActivityBlock):  			// UNDO BLOCK  			ASBlock, ok := iter.GetType().(vocab.ActivityStreamsBlock)  			if !ok { diff --git a/internal/federation/federatingdb/update.go b/internal/federation/federatingdb/update.go index e9dfe5315..2bcf2533c 100644 --- a/internal/federation/federatingdb/update.go +++ b/internal/federation/federatingdb/update.go @@ -29,6 +29,7 @@ import (  	"github.com/sirupsen/logrus"  	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) @@ -84,50 +85,50 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {  	if fromFederatorChanI == nil {  		l.Error("UPDATE: from federator channel wasn't set on context")  	} -	fromFederatorChan, ok := fromFederatorChanI.(chan gtsmodel.FromFederator) +	fromFederatorChan, ok := fromFederatorChanI.(chan messages.FromFederator)  	if !ok {  		l.Error("UPDATE: from federator channel was set on context but couldn't be parsed")  	}  	typeName := asType.GetTypeName() -	if typeName == gtsmodel.ActivityStreamsApplication || -		typeName == gtsmodel.ActivityStreamsGroup || -		typeName == gtsmodel.ActivityStreamsOrganization || -		typeName == gtsmodel.ActivityStreamsPerson || -		typeName == gtsmodel.ActivityStreamsService { +	if typeName == ap.ActorApplication || +		typeName == ap.ActorGroup || +		typeName == ap.ActorOrganization || +		typeName == ap.ActorPerson || +		typeName == ap.ActorService {  		// it's an UPDATE to some kind of account  		var accountable ap.Accountable  		switch asType.GetTypeName() { -		case gtsmodel.ActivityStreamsApplication: +		case ap.ActorApplication:  			l.Debug("got update for APPLICATION")  			i, ok := asType.(vocab.ActivityStreamsApplication)  			if !ok {  				return errors.New("UPDATE: could not convert type to application")  			}  			accountable = i -		case gtsmodel.ActivityStreamsGroup: +		case ap.ActorGroup:  			l.Debug("got update for GROUP")  			i, ok := asType.(vocab.ActivityStreamsGroup)  			if !ok {  				return errors.New("UPDATE: could not convert type to group")  			}  			accountable = i -		case gtsmodel.ActivityStreamsOrganization: +		case ap.ActorOrganization:  			l.Debug("got update for ORGANIZATION")  			i, ok := asType.(vocab.ActivityStreamsOrganization)  			if !ok {  				return errors.New("UPDATE: could not convert type to organization")  			}  			accountable = i -		case gtsmodel.ActivityStreamsPerson: +		case ap.ActorPerson:  			l.Debug("got update for PERSON")  			i, ok := asType.(vocab.ActivityStreamsPerson)  			if !ok {  				return errors.New("UPDATE: could not convert type to person")  			}  			accountable = i -		case gtsmodel.ActivityStreamsService: +		case ap.ActorService:  			l.Debug("got update for SERVICE")  			i, ok := asType.(vocab.ActivityStreamsService)  			if !ok { @@ -157,9 +158,9 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {  			return fmt.Errorf("UPDATE: database error inserting updated account: %s", err)  		} -		fromFederatorChan <- gtsmodel.FromFederator{ -			APObjectType:     gtsmodel.ActivityStreamsProfile, -			APActivityType:   gtsmodel.ActivityStreamsUpdate, +		fromFederatorChan <- messages.FromFederator{ +			APObjectType:     ap.ObjectProfile, +			APActivityType:   ap.ActivityUpdate,  			GTSModel:         updatedAcct,  			ReceivingAccount: targetAcct,  		} diff --git a/internal/federation/federatingdb/util.go b/internal/federation/federatingdb/util.go index b5befc613..d8c7d8e8a 100644 --- a/internal/federation/federatingdb/util.go +++ b/internal/federation/federatingdb/util.go @@ -28,6 +28,7 @@ import (  	"github.com/go-fed/activity/streams"  	"github.com/go-fed/activity/streams/vocab"  	"github.com/sirupsen/logrus" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/id" @@ -78,7 +79,7 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,  	l.Debugf("received NEWID request for asType %s", string(b))  	switch t.GetTypeName() { -	case gtsmodel.ActivityStreamsFollow: +	case ap.ActivityFollow:  		// FOLLOW  		// ID might already be set on a follow we've created, so check it here and return it if it is  		follow, ok := t.(vocab.ActivityStreamsFollow) @@ -108,7 +109,7 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,  				}  			}  		} -	case gtsmodel.ActivityStreamsNote: +	case ap.ObjectNote:  		// NOTE aka STATUS  		// ID might already be set on a note we've created, so check it here and return it if it is  		note, ok := t.(vocab.ActivityStreamsNote) @@ -121,7 +122,7 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,  				return idProp.GetIRI(), nil  			}  		} -	case gtsmodel.ActivityStreamsLike: +	case ap.ActivityLike:  		// LIKE aka FAVE  		// ID might already be set on a fave we've created, so check it here and return it if it is  		fave, ok := t.(vocab.ActivityStreamsLike) @@ -134,7 +135,7 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,  				return idProp.GetIRI(), nil  			}  		} -	case gtsmodel.ActivityStreamsAnnounce: +	case ap.ActivityAnnounce:  		// ANNOUNCE aka BOOST  		// ID might already be set on an announce we've created, so check it here and return it if it is  		announce, ok := t.(vocab.ActivityStreamsAnnounce) @@ -147,7 +148,7 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,  				return idProp.GetIRI(), nil  			}  		} -	case gtsmodel.ActivityStreamsUpdate: +	case ap.ActivityUpdate:  		// UPDATE  		// ID might already be set on an update we've created, so check it here and return it if it is  		update, ok := t.(vocab.ActivityStreamsUpdate) @@ -160,7 +161,7 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,  				return idProp.GetIRI(), nil  			}  		} -	case gtsmodel.ActivityStreamsBlock: +	case ap.ActivityBlock:  		// BLOCK  		// ID might already be set on a block we've created, so check it here and return it if it is  		block, ok := t.(vocab.ActivityStreamsBlock) @@ -173,7 +174,7 @@ func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL,  				return idProp.GetIRI(), nil  			}  		} -	case gtsmodel.ActivityStreamsUndo: +	case ap.ActivityUndo:  		// UNDO  		// ID might already be set on an undo we've created, so check it here and return it if it is  		undo, ok := t.(vocab.ActivityStreamsUndo) diff --git a/internal/gtsmodel/activitystreams.go b/internal/gtsmodel/activitystreams.go deleted file mode 100644 index 5cd92015c..000000000 --- a/internal/gtsmodel/activitystreams.go +++ /dev/null @@ -1,122 +0,0 @@ -/* -   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 gtsmodel - -const ( -	// ActivityStreamsArticle https://www.w3.org/TR/activitystreams-vocabulary/#dfn-article -	ActivityStreamsArticle = "Article" -	// ActivityStreamsAudio https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audio -	ActivityStreamsAudio = "Audio" -	// ActivityStreamsDocument https://www.w3.org/TR/activitystreams-vocabulary/#dfn-document -	ActivityStreamsDocument = "Document" -	// ActivityStreamsEvent https://www.w3.org/TR/activitystreams-vocabulary/#dfn-event -	ActivityStreamsEvent = "Event" -	// ActivityStreamsImage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image -	ActivityStreamsImage = "Image" -	// ActivityStreamsNote https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note -	ActivityStreamsNote = "Note" -	// ActivityStreamsPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-page -	ActivityStreamsPage = "Page" -	// ActivityStreamsPlace https://www.w3.org/TR/activitystreams-vocabulary/#dfn-place -	ActivityStreamsPlace = "Place" -	// ActivityStreamsProfile https://www.w3.org/TR/activitystreams-vocabulary/#dfn-profile -	ActivityStreamsProfile = "Profile" -	// ActivityStreamsRelationship https://www.w3.org/TR/activitystreams-vocabulary/#dfn-relationship -	ActivityStreamsRelationship = "Relationship" -	// ActivityStreamsTombstone https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone -	ActivityStreamsTombstone = "Tombstone" -	// ActivityStreamsVideo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-video -	ActivityStreamsVideo = "Video" -	//ActivityStreamsCollection https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collection -	ActivityStreamsCollection = "Collection" -	// ActivityStreamsCollectionPage https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage -	ActivityStreamsCollectionPage = "CollectionPage" -) - -const ( -	// ActivityStreamsApplication https://www.w3.org/TR/activitystreams-vocabulary/#dfn-application -	ActivityStreamsApplication = "Application" -	// ActivityStreamsGroup https://www.w3.org/TR/activitystreams-vocabulary/#dfn-group -	ActivityStreamsGroup = "Group" -	// ActivityStreamsOrganization https://www.w3.org/TR/activitystreams-vocabulary/#dfn-organization -	ActivityStreamsOrganization = "Organization" -	// ActivityStreamsPerson https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person -	ActivityStreamsPerson = "Person" -	// ActivityStreamsService https://www.w3.org/TR/activitystreams-vocabulary/#dfn-service -	ActivityStreamsService = "Service" -) - -const ( -	// ActivityStreamsAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept -	ActivityStreamsAccept = "Accept" -	// ActivityStreamsAdd https://www.w3.org/TR/activitystreams-vocabulary/#dfn-add -	ActivityStreamsAdd = "Add" -	// ActivityStreamsAnnounce https://www.w3.org/TR/activitystreams-vocabulary/#dfn-announce -	ActivityStreamsAnnounce = "Announce" -	// ActivityStreamsArrive https://www.w3.org/TR/activitystreams-vocabulary/#dfn-arrive -	ActivityStreamsArrive = "Arrive" -	// ActivityStreamsBlock https://www.w3.org/TR/activitystreams-vocabulary/#dfn-block -	ActivityStreamsBlock = "Block" -	// ActivityStreamsCreate https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create -	ActivityStreamsCreate = "Create" -	// ActivityStreamsDelete https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete -	ActivityStreamsDelete = "Delete" -	// ActivityStreamsDislike https://www.w3.org/TR/activitystreams-vocabulary/#dfn-dislike -	ActivityStreamsDislike = "Dislike" -	// ActivityStreamsFlag https://www.w3.org/TR/activitystreams-vocabulary/#dfn-flag -	ActivityStreamsFlag = "Flag" -	// ActivityStreamsFollow https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow -	ActivityStreamsFollow = "Follow" -	// ActivityStreamsIgnore https://www.w3.org/TR/activitystreams-vocabulary/#dfn-ignore -	ActivityStreamsIgnore = "Ignore" -	// ActivityStreamsInvite https://www.w3.org/TR/activitystreams-vocabulary/#dfn-invite -	ActivityStreamsInvite = "Invite" -	// ActivityStreamsJoin https://www.w3.org/TR/activitystreams-vocabulary/#dfn-join -	ActivityStreamsJoin = "Join" -	// ActivityStreamsLeave https://www.w3.org/TR/activitystreams-vocabulary/#dfn-leave -	ActivityStreamsLeave = "Leave" -	// ActivityStreamsLike https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like -	ActivityStreamsLike = "Like" -	// ActivityStreamsListen https://www.w3.org/TR/activitystreams-vocabulary/#dfn-listen -	ActivityStreamsListen = "Listen" -	// ActivityStreamsMove https://www.w3.org/TR/activitystreams-vocabulary/#dfn-move -	ActivityStreamsMove = "Move" -	// ActivityStreamsOffer https://www.w3.org/TR/activitystreams-vocabulary/#dfn-offer -	ActivityStreamsOffer = "Offer" -	// ActivityStreamsQuestion https://www.w3.org/TR/activitystreams-vocabulary/#dfn-question -	ActivityStreamsQuestion = "Question" -	// ActivityStreamsReject https://www.w3.org/TR/activitystreams-vocabulary/#dfn-reject -	ActivityStreamsReject = "Reject" -	// ActivityStreamsRead https://www.w3.org/TR/activitystreams-vocabulary/#dfn-read -	ActivityStreamsRead = "Read" -	// ActivityStreamsRemove https://www.w3.org/TR/activitystreams-vocabulary/#dfn-remove -	ActivityStreamsRemove = "Remove" -	// ActivityStreamsTentativeReject https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tentativereject -	ActivityStreamsTentativeReject = "TentativeReject" -	// ActivityStreamsTentativeAccept https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tentativeaccept -	ActivityStreamsTentativeAccept = "TentativeAccept" -	// ActivityStreamsTravel https://www.w3.org/TR/activitystreams-vocabulary/#dfn-travel -	ActivityStreamsTravel = "Travel" -	// ActivityStreamsUndo https://www.w3.org/TR/activitystreams-vocabulary/#dfn-undo -	ActivityStreamsUndo = "Undo" -	// ActivityStreamsUpdate https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update -	ActivityStreamsUpdate = "Update" -	// ActivityStreamsView https://www.w3.org/TR/activitystreams-vocabulary/#dfn-view -	ActivityStreamsView = "View" -) diff --git a/internal/gtsmodel/application.go b/internal/gtsmodel/application.go index 12a21d298..0791aae6a 100644 --- a/internal/gtsmodel/application.go +++ b/internal/gtsmodel/application.go @@ -21,20 +21,12 @@ package gtsmodel  // Application represents an application that can perform actions on behalf of a user.  // It is used to authorize tokens etc, and is associated with an oauth client id in the database.  type Application struct { -	// id of this application in the db -	ID string `bun:"type:CHAR(26),pk,notnull"` -	// name of the application given when it was created (eg., 'tusky') -	Name string `bun:",nullzero"` -	// website for the application given when it was created (eg., 'https://tusky.app') -	Website string `bun:",nullzero"` -	// redirect uri requested by the application for oauth2 flow -	RedirectURI string `bun:",nullzero"` -	// id of the associated oauth client entity in the db -	ClientID string `bun:"type:CHAR(26),nullzero"` -	// secret of the associated oauth client entity in the db -	ClientSecret string `bun:",nullzero"` -	// scopes requested when this app was created -	Scopes string `bun:",nullzero"` -	// a vapid key generated for this app when it was created -	VapidKey string `bun:",nullzero"` +	ID           string `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull"` // id of this application in the db +	Name         string `validate:"required" bun:",nullzero,notnull"`                      // name of the application given when it was created (eg., 'tusky') +	Website      string `validate:"omitempty,url" bun:",nullzero"`                         // website for the application given when it was created (eg., 'https://tusky.app') +	RedirectURI  string `validate:"required" bun:",nullzero,notnull"`                      // redirect uri requested by the application for oauth2 flow +	ClientID     string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"`           // id of the associated oauth client entity in the db +	ClientSecret string `validate:"required,uuid" bun:",nullzero,notnull"`                 // secret of the associated oauth client entity in the db +	Scopes       string `validate:"required" bun:",nullzero,default:'read'"`               // scopes requested when this app was created +	VapidKey     string `validate:"-" bun:",nullzero"`                                     // a vapid key generated for this app when it was created  } diff --git a/internal/gtsmodel/block.go b/internal/gtsmodel/block.go index 0c762837d..989dd8193 100644 --- a/internal/gtsmodel/block.go +++ b/internal/gtsmodel/block.go @@ -4,18 +4,12 @@ import "time"  // Block refers to the blocking of one account by another.  type Block struct { -	// id of this block in the database -	ID string `bun:"type:CHAR(26),pk,notnull"` -	// When was this block created -	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// When was this block updated -	UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// Who created this block? -	AccountID string   `bun:"type:CHAR(26),notnull"` -	Account   *Account `bun:"rel:belongs-to"` -	// Who is targeted by this block? -	TargetAccountID string   `bun:"type:CHAR(26),notnull"` -	TargetAccount   *Account `bun:"rel:belongs-to"` -	// Activitypub URI for this block -	URI string `bun:",notnull"` +	ID              string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database +	CreatedAt       time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created +	UpdatedAt       time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item last updated +	URI             string    `validate:"required,url" bun:",notnull,nullzero,unique"`                  // ActivityPub uri of this block. +	AccountID       string    `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull"` // Who does this block originate from? +	Account         *Account  `validate:"-" bun:"rel:belongs-to"`                                       // Account corresponding to accountID +	TargetAccountID string    `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull"` // Who is the target of this block ? +	TargetAccount   *Account  `validate:"-" bun:"rel:belongs-to"`                                       // Account corresponding to targetAccountID  } diff --git a/internal/gtsmodel/domainblock.go b/internal/gtsmodel/domainblock.go index 784e665a5..dd05ef0c6 100644 --- a/internal/gtsmodel/domainblock.go +++ b/internal/gtsmodel/domainblock.go @@ -22,23 +22,14 @@ import "time"  // DomainBlock represents a federation block against a particular domain  type DomainBlock struct { -	// ID of this block in the database -	ID string `bun:"type:CHAR(26),pk,notnull,unique"` -	// blocked domain -	Domain string `bun:",pk,notnull,unique"` -	// When was this block created -	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// When was this block updated -	UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// Account ID of the creator of this block -	CreatedByAccountID string   `bun:"type:CHAR(26),notnull"` -	CreatedByAccount   *Account `bun:"rel:belongs-to"` -	// Private comment on this block, viewable to admins -	PrivateComment string `bun:",nullzero"` -	// Public comment on this block, viewable (optionally) by everyone -	PublicComment string `bun:",nullzero"` -	// whether the domain name should appear obfuscated when displaying it publicly -	Obfuscate bool -	// if this block was created through a subscription, what's the subscription ID? -	SubscriptionID string `bun:"type:CHAR(26),nullzero"` +	ID                 string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database +	CreatedAt          time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created +	UpdatedAt          time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item last updated +	Domain             string    `validate:"required,fqdn" bun:",nullzero,notnull"`                        // domain to block. Eg. 'whatever.com' +	CreatedByAccountID string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`           // Account ID of the creator of this block +	CreatedByAccount   *Account  `validate:"-" bun:"rel:belongs-to"`                                       // Account corresponding to createdByAccountID +	PrivateComment     string    `validate:"-" bun:",nullzero"`                                            // Private comment on this block, viewable to admins +	PublicComment      string    `validate:"-" bun:",nullzero"`                                            // Public comment on this block, viewable (optionally) by everyone +	Obfuscate          bool      `validate:"-" bun:",nullzero,default:false"`                              // whether the domain name should appear obfuscated when displaying it publicly +	SubscriptionID     string    `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"`                  // if this block was created through a subscription, what's the subscription ID?  } diff --git a/internal/gtsmodel/emaildomainblock.go b/internal/gtsmodel/emaildomainblock.go index 1919172fa..38f4a9580 100644 --- a/internal/gtsmodel/emaildomainblock.go +++ b/internal/gtsmodel/emaildomainblock.go @@ -22,15 +22,10 @@ import "time"  // EmailDomainBlock represents a domain that the server should automatically reject sign-up requests from.  type EmailDomainBlock struct { -	// ID of this block in the database -	ID string `bun:"type:CHAR(26),pk,notnull,unique"` -	// Email domain to block. Eg. 'gmail.com' or 'hotmail.com' -	Domain string `bun:",notnull"` -	// When was this block created -	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// When was this block updated -	UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// Account ID of the creator of this block -	CreatedByAccountID string   `bun:"type:CHAR(26),notnull"` -	CreatedByAccount   *Account `bun:"rel:belongs-to"` +	ID                 string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database +	CreatedAt          time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created +	UpdatedAt          time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item last updated +	Domain             string    `validate:"required,fqdn" bun:",nullzero,notnull"`                        // Email domain to block. Eg. 'gmail.com' or 'hotmail.com' +	CreatedByAccountID string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`           // Account ID of the creator of this block +	CreatedByAccount   *Account  `validate:"-" bun:"rel:belongs-to"`                                       // Account corresponding to createdByAccountID  } diff --git a/internal/gtsmodel/emoji.go b/internal/gtsmodel/emoji.go index 9723f0790..71287130a 100644 --- a/internal/gtsmodel/emoji.go +++ b/internal/gtsmodel/emoji.go @@ -22,56 +22,24 @@ import "time"  // Emoji represents a custom emoji that's been uploaded through the admin UI, and is useable by instance denizens.  type Emoji struct { -	// database ID of this emoji -	ID string `bun:"type:CHAR(26),pk,notnull"` -	// String shortcode for this emoji -- the part that's between colons. This should be lowercase a-z_ -	// eg., 'blob_hug' 'purple_heart' Must be unique with domain. -	Shortcode string `bun:",notnull,unique:shortcodedomain"` -	// Origin domain of this emoji, eg 'example.org', 'queer.party'. empty string for local emojis. -	Domain string `bun:",notnull,default:'',unique:shortcodedomain"` -	// When was this emoji created. Must be unique with shortcode. -	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// When was this emoji updated -	UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// Where can this emoji be retrieved remotely? Null for local emojis. -	// For remote emojis, it'll be something like: -	// https://hackers.town/system/custom_emojis/images/000/049/842/original/1b74481204feabfd.png -	ImageRemoteURL string `bun:",nullzero"` -	// Where can a static / non-animated version of this emoji be retrieved remotely? Null for local emojis. -	// For remote emojis, it'll be something like: -	// https://hackers.town/system/custom_emojis/images/000/049/842/static/1b74481204feabfd.png -	ImageStaticRemoteURL string `bun:",nullzero"` -	// Where can this emoji be retrieved from the local server? Null for remote emojis. -	// Assuming our server is hosted at 'example.org', this will be something like: -	// 'https://example.org/fileserver/6339820e-ef65-4166-a262-5a9f46adb1a7/emoji/original/bfa6c9c5-6c25-4ea4-98b4-d78b8126fb52.png' -	ImageURL string `bun:",nullzero"` -	// Where can a static version of this emoji be retrieved from the local server? Null for remote emojis. -	// Assuming our server is hosted at 'example.org', this will be something like: -	// 'https://example.org/fileserver/6339820e-ef65-4166-a262-5a9f46adb1a7/emoji/small/bfa6c9c5-6c25-4ea4-98b4-d78b8126fb52.png' -	ImageStaticURL string `bun:",nullzero"` -	// Path of the emoji image in the server storage system. Will be something like: -	// '/gotosocial/storage/6339820e-ef65-4166-a262-5a9f46adb1a7/emoji/original/bfa6c9c5-6c25-4ea4-98b4-d78b8126fb52.png' -	ImagePath string `bun:",notnull"` -	// Path of a static version of the emoji image in the server storage system. Will be something like: -	// '/gotosocial/storage/6339820e-ef65-4166-a262-5a9f46adb1a7/emoji/small/bfa6c9c5-6c25-4ea4-98b4-d78b8126fb52.png' -	ImageStaticPath string `bun:",notnull"` -	// MIME content type of the emoji image -	// Probably "image/png" -	ImageContentType string `bun:",notnull"` -	// MIME content type of the static version of the emoji image. -	ImageStaticContentType string `bun:",notnull"` -	// Size of the emoji image file in bytes, for serving purposes. -	ImageFileSize int `bun:",notnull"` -	// Size of the static version of the emoji image file in bytes, for serving purposes. -	ImageStaticFileSize int `bun:",notnull"` -	// When was the emoji image last updated? -	ImageUpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// Has a moderation action disabled this emoji from being shown? -	Disabled bool `bun:",notnull,default:false"` -	// ActivityStreams uri of this emoji. Something like 'https://example.org/emojis/1234' -	URI string `bun:",notnull,unique"` -	// Is this emoji visible in the admin emoji picker? -	VisibleInPicker bool `bun:",notnull,default:true"` -	// In which emoji category is this emoji visible? -	CategoryID string `bun:"type:CHAR(26),nullzero"` +	ID                     string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                                // id of this item in the database +	CreatedAt              time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`                                         // when was item created +	UpdatedAt              time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`                                         // when was item last updated +	Shortcode              string    `validate:"required" bun:",notnull,unique:shortcodedomain"`                                              // String shortcode for this emoji -- the part that's between colons. This should be lowercase a-z_  eg., 'blob_hug' 'purple_heart' Must be unique with domain. +	Domain                 string    `validate:"omitempty,fqdn" bun:",notnull,default:'',unique:shortcodedomain"`                             // Origin domain of this emoji, eg 'example.org', 'queer.party'. empty string for local emojis. +	ImageRemoteURL         string    `validate:"required_without=ImageURL,omitempty,url" bun:",nullzero"`                                     // Where can this emoji be retrieved remotely? Null for local emojis. +	ImageStaticRemoteURL   string    `validate:"required_without=ImageStaticURL,omitempty,url" bun:",nullzero"`                               // Where can a static / non-animated version of this emoji be retrieved remotely? Null for local emojis. +	ImageURL               string    `validate:"required_without=ImageRemoteURL,required_without=Domain,omitempty,url" bun:",nullzero"`       // Where can this emoji be retrieved from the local server? Null for remote emojis. +	ImageStaticURL         string    `validate:"required_without=ImageStaticRemoteURL,required_without=Domain,omitempty,url" bun:",nullzero"` // Where can a static version of this emoji be retrieved from the local server? Null for remote emojis. +	ImagePath              string    `validate:"required,file" bun:",nullzero,notnull"`                                                       // Path of the emoji image in the server storage system. +	ImageStaticPath        string    `validate:"required,file" bun:",nullzero,notnull"`                                                       // Path of a static version of the emoji image in the server storage system +	ImageContentType       string    `validate:"required" bun:",nullzero,notnull"`                                                            // MIME content type of the emoji image +	ImageStaticContentType string    `validate:"required" bun:",nullzero,notnull"`                                                            // MIME content type of the static version of the emoji image. +	ImageFileSize          int       `validate:"required,min=1" bun:",nullzero,notnull"`                                                      // Size of the emoji image file in bytes, for serving purposes. +	ImageStaticFileSize    int       `validate:"required,min=1" bun:",nullzero,notnull"`                                                      // Size of the static version of the emoji image file in bytes, for serving purposes. +	ImageUpdatedAt         time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`                                         // When was the emoji image last updated? +	Disabled               bool      `validate:"-" bun:",notnull,default:false"`                                                              // Has a moderation action disabled this emoji from being shown? +	URI                    string    `validate:"url" bun:",nullzero,notnull,unique"`                                                          // ActivityPub uri of this emoji. Something like 'https://example.org/emojis/1234' +	VisibleInPicker        bool      `validate:"-" bun:",notnull,default:true"`                                                               // Is this emoji visible in the admin emoji picker? +	CategoryID             string    `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"`                                                 // In which emoji category is this emoji visible?  } diff --git a/internal/gtsmodel/emoji_test.go b/internal/gtsmodel/emoji_test.go new file mode 100644 index 000000000..a0b48040c --- /dev/null +++ b/internal/gtsmodel/emoji_test.go @@ -0,0 +1,194 @@ +/* +   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 gtsmodel_test + +import ( +	"os" +	"testing" +	"time" + +	"github.com/stretchr/testify/suite" +	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +func happyEmoji() *gtsmodel.Emoji { +	// the file validator actually runs os.Stat on given paths, so we need to just create small +	// temp files for both the main attachment file and the thumbnail + +	imageFile, err := os.CreateTemp("", "gts_test_emoji") +	if err != nil { +		panic(err) +	} +	if _, err := imageFile.WriteString("main"); err != nil { +		panic(err) +	} +	imagePath := imageFile.Name() +	if err := imageFile.Close(); err != nil { +		panic(err) +	} + +	staticFile, err := os.CreateTemp("", "gts_test_emoji_static") +	if err != nil { +		panic(err) +	} +	if _, err := staticFile.WriteString("thumbnail"); err != nil { +		panic(err) +	} +	imageStaticPath := staticFile.Name() +	if err := staticFile.Close(); err != nil { +		panic(err) +	} + +	return >smodel.Emoji{ +		ID:                     "01F8MH6NEM8D7527KZAECTCR76", +		CreatedAt:              time.Now().Add(-71 * time.Hour), +		UpdatedAt:              time.Now().Add(-71 * time.Hour), +		Shortcode:              "blob_test", +		Domain:                 "example.org", +		ImageRemoteURL:         "https://example.org/emojis/blob_test.gif", +		ImageStaticRemoteURL:   "https://example.org/emojis/blob_test.png", +		ImageURL:               "", +		ImageStaticURL:         "", +		ImagePath:              imagePath, +		ImageStaticPath:        imageStaticPath, +		ImageContentType:       "image/gif", +		ImageStaticContentType: "image/png", +		ImageFileSize:          1024, +		ImageStaticFileSize:    256, +		ImageUpdatedAt:         time.Now(), +		Disabled:               false, +		URI:                    "https://example.org/emojis/blob_test", +		VisibleInPicker:        true, +		CategoryID:             "01FEE47ZH70PWDSEAVBRFNX325", +	} +} + +type EmojiValidateTestSuite struct { +	suite.Suite +} + +func (suite *EmojiValidateTestSuite) TestValidateEmojiHappyPath() { +	// no problem here +	m := happyEmoji() +	err := gtsmodel.ValidateStruct(*m) +	suite.NoError(err) +} + +func (suite *EmojiValidateTestSuite) TestValidateEmojiBadFilePaths() { +	e := happyEmoji() + +	e.ImagePath = "/tmp/nonexistent/file/for/gotosocial/test" +	err := gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag") + +	e.ImagePath = "" +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'required' tag") + +	e.ImagePath = "???????????thisnot a valid path####" +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag") + +	e.ImageStaticPath = "/tmp/nonexistent/file/for/gotosocial/test" +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag\nKey: 'Emoji.ImageStaticPath' Error:Field validation for 'ImageStaticPath' failed on the 'file' tag") + +	e.ImageStaticPath = "" +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag\nKey: 'Emoji.ImageStaticPath' Error:Field validation for 'ImageStaticPath' failed on the 'required' tag") + +	e.ImageStaticPath = "???????????thisnot a valid path####" +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImagePath' Error:Field validation for 'ImagePath' failed on the 'file' tag\nKey: 'Emoji.ImageStaticPath' Error:Field validation for 'ImageStaticPath' failed on the 'file' tag") +} + +func (suite *EmojiValidateTestSuite) TestValidateEmojiURI() { +	e := happyEmoji() + +	e.URI = "aaaaaaaaaa" +	err := gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.URI' Error:Field validation for 'URI' failed on the 'url' tag") + +	e.URI = "" +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.URI' Error:Field validation for 'URI' failed on the 'url' tag") +} + +func (suite *EmojiValidateTestSuite) TestValidateEmojiURLCombos() { +	e := happyEmoji() + +	e.ImageRemoteURL = "" +	err := gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImageRemoteURL' Error:Field validation for 'ImageRemoteURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageURL' Error:Field validation for 'ImageURL' failed on the 'required_without' tag") + +	e.ImageURL = "https://whatever.org" +	err = gtsmodel.ValidateStruct(*e) +	suite.NoError(err) + +	e.ImageStaticRemoteURL = "" +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImageStaticRemoteURL' Error:Field validation for 'ImageStaticRemoteURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageStaticURL' Error:Field validation for 'ImageStaticURL' failed on the 'required_without' tag") + +	e.ImageStaticURL = "https://whatever.org" +	err = gtsmodel.ValidateStruct(*e) +	suite.NoError(err) + +	e.ImageURL = "" +	e.ImageStaticURL = "" +	e.ImageRemoteURL = "" +	e.ImageStaticRemoteURL = "" +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImageRemoteURL' Error:Field validation for 'ImageRemoteURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageStaticRemoteURL' Error:Field validation for 'ImageStaticRemoteURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageURL' Error:Field validation for 'ImageURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageStaticURL' Error:Field validation for 'ImageStaticURL' failed on the 'required_without' tag") +} + +func (suite *EmojiValidateTestSuite) TestValidateFileSize() { +	e := happyEmoji() + +	e.ImageFileSize = 0 +	err := gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImageFileSize' Error:Field validation for 'ImageFileSize' failed on the 'required' tag") + +	e.ImageStaticFileSize = 0 +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImageFileSize' Error:Field validation for 'ImageFileSize' failed on the 'required' tag\nKey: 'Emoji.ImageStaticFileSize' Error:Field validation for 'ImageStaticFileSize' failed on the 'required' tag") + +	e.ImageFileSize = -1 +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImageFileSize' Error:Field validation for 'ImageFileSize' failed on the 'min' tag\nKey: 'Emoji.ImageStaticFileSize' Error:Field validation for 'ImageStaticFileSize' failed on the 'required' tag") + +	e.ImageStaticFileSize = -1 +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImageFileSize' Error:Field validation for 'ImageFileSize' failed on the 'min' tag\nKey: 'Emoji.ImageStaticFileSize' Error:Field validation for 'ImageStaticFileSize' failed on the 'min' tag") +} + +func (suite *EmojiValidateTestSuite) TestValidateDomain() { +	e := happyEmoji() + +	e.Domain = "" +	err := gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.ImageURL' Error:Field validation for 'ImageURL' failed on the 'required_without' tag\nKey: 'Emoji.ImageStaticURL' Error:Field validation for 'ImageStaticURL' failed on the 'required_without' tag") + +	e.Domain = "aaaaaaaaa" +	err = gtsmodel.ValidateStruct(*e) +	suite.EqualError(err, "Key: 'Emoji.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") +} + +func TestEmojiValidateTestSuite(t *testing.T) { +	suite.Run(t, new(EmojiValidateTestSuite)) +} diff --git a/internal/gtsmodel/follow.go b/internal/gtsmodel/follow.go index 1e1095af9..8b03db56a 100644 --- a/internal/gtsmodel/follow.go +++ b/internal/gtsmodel/follow.go @@ -22,22 +22,14 @@ import "time"  // Follow represents one account following another, and the metadata around that follow.  type Follow struct { -	// id of this follow in the database -	ID string `bun:"type:CHAR(26),pk,notnull,unique"` -	// When was this follow created? -	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// When was this follow last updated? -	UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// Who does this follow belong to? -	AccountID string   `bun:"type:CHAR(26),unique:srctarget,notnull"` -	Account   *Account `bun:"rel:belongs-to"` -	// Who does AccountID follow? -	TargetAccountID string   `bun:"type:CHAR(26),unique:srctarget,notnull"` -	TargetAccount   *Account `bun:"rel:belongs-to"` -	// Does this follow also want to see reblogs and not just posts? -	ShowReblogs bool `bun:"default:true"` -	// What is the activitypub URI of this follow? -	URI string `bun:",unique,nullzero"` -	// does the following account want to be notified when the followed account posts? -	Notify bool +	ID              string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database +	CreatedAt       time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created +	UpdatedAt       time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item last updated +	URI             string    `validate:"required,url" bun:",notnull,nullzero,unique"`                  // ActivityPub uri of this follow. +	AccountID       string    `validate:"required,ulid" bun:"type:CHAR(26),unique:srctarget,notnull"` // Who does this follow originate from? +	Account         *Account  `validate:"-" bun:"rel:belongs-to"`                                       // Account corresponding to accountID +	TargetAccountID string    `validate:"required,ulid" bun:"type:CHAR(26),unique:srctarget,notnull"` // Who is the target of this follow ? +	TargetAccount   *Account  `validate:"-" bun:"rel:belongs-to"`                                       // Account corresponding to targetAccountID +	ShowReblogs     bool      `validate:"-" bun:",nullzero,default:true"`                                // Does this follow also want to see reblogs and not just posts? +	Notify          bool      `validate:"-" bun:",nullzero,default:false"`                              // does the following account want to be notified when the followed account posts?  } diff --git a/internal/gtsmodel/follow_test.go b/internal/gtsmodel/follow_test.go new file mode 100644 index 000000000..2af0f5e4f --- /dev/null +++ b/internal/gtsmodel/follow_test.go @@ -0,0 +1,87 @@ +/* +   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 gtsmodel_test + +import ( +	"testing" +	"time" + +	"github.com/stretchr/testify/suite" +	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +func happyFollow() *gtsmodel.Follow { +	return >smodel.Follow{ +		ID:              "01FE91RJR88PSEEE30EV35QR8N", +		CreatedAt:       time.Now(), +		UpdatedAt:       time.Now(), +		AccountID:       "01FE96MAE58MXCE5C4SSMEMCEK", +		Account:         nil, +		TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A", +		TargetAccount:   nil, +		URI:             "https://example.org/users/user1/activity/follow/01FE91RJR88PSEEE30EV35QR8N", +	} +} + +type FollowValidateTestSuite struct { +	suite.Suite +} + +func (suite *FollowValidateTestSuite) TestValidateFollowHappyPath() { +	// no problem here +	f := happyFollow() +	err := gtsmodel.ValidateStruct(*f) +	suite.NoError(err) +} + +func (suite *FollowValidateTestSuite) TestValidateFollowBadID() { +	f := happyFollow() + +	f.ID = "" +	err := gtsmodel.ValidateStruct(*f) +	suite.EqualError(err, "Key: 'Follow.ID' Error:Field validation for 'ID' failed on the 'required' tag") + +	f.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" +	err = gtsmodel.ValidateStruct(*f) +	suite.EqualError(err, "Key: 'Follow.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") +} + +func (suite *FollowValidateTestSuite) TestValidateFollowNoCreatedAt() { +	f := happyFollow() + +	f.CreatedAt = time.Time{} +	err := gtsmodel.ValidateStruct(*f) +	suite.NoError(err) +} + +func (suite *FollowValidateTestSuite) TestValidateFollowNoURI() { +	f := happyFollow() + +	f.URI = "" +	err := gtsmodel.ValidateStruct(*f) +	suite.EqualError(err, "Key: 'Follow.URI' Error:Field validation for 'URI' failed on the 'required' tag") + +	f.URI = "this-is-not-a-valid-url" +	err = gtsmodel.ValidateStruct(*f) +	suite.EqualError(err, "Key: 'Follow.URI' Error:Field validation for 'URI' failed on the 'url' tag") +} + +func TestFollowValidateTestSuite(t *testing.T) { +	suite.Run(t, new(FollowValidateTestSuite)) +} diff --git a/internal/gtsmodel/followrequest.go b/internal/gtsmodel/followrequest.go index 5a6cb5e02..c4b3c9997 100644 --- a/internal/gtsmodel/followrequest.go +++ b/internal/gtsmodel/followrequest.go @@ -22,22 +22,14 @@ import "time"  // FollowRequest represents one account requesting to follow another, and the metadata around that request.  type FollowRequest struct { -	// id of this follow request in the database -	ID string `bun:"type:CHAR(26),pk,notnull,unique"` -	// When was this follow request created? -	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// When was this follow request last updated? -	UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// Who does this follow request originate from? -	AccountID string   `bun:"type:CHAR(26),unique:frsrctarget,notnull"` -	Account   *Account `bun:"rel:belongs-to"` -	// Who is the target of this follow request? -	TargetAccountID string   `bun:"type:CHAR(26),unique:frsrctarget,notnull"` -	TargetAccount   *Account `bun:"rel:belongs-to"` -	// Does this follow also want to see reblogs and not just posts? -	ShowReblogs bool `bun:"default:true"` -	// What is the activitypub URI of this follow request? -	URI string `bun:",unique,nullzero"` -	// does the following account want to be notified when the followed account posts? -	Notify bool +	ID              string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database +	CreatedAt       time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created +	UpdatedAt       time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item last updated +	URI             string    `validate:"required,url" bun:",notnull,nullzero,unique"`                  // ActivityPub uri of this follow (request). +	AccountID       string    `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull"` // Who does this follow request originate from? +	Account         *Account  `validate:"-" bun:"rel:belongs-to"`                                       // Account corresponding to accountID +	TargetAccountID string    `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull"` // Who is the target of this follow request? +	TargetAccount   *Account  `validate:"-" bun:"rel:belongs-to"`                                       // Account corresponding to targetAccountID +	ShowReblogs     bool      `validate:"-" bun:",nullzero,default:true"`                                // Does this follow also want to see reblogs and not just posts? +	Notify          bool      `validate:"-" bun:",nullzero,default:false"`                              // does the following account want to be notified when the followed account posts?  } diff --git a/internal/gtsmodel/followrequest_test.go b/internal/gtsmodel/followrequest_test.go new file mode 100644 index 000000000..a3ae8ded8 --- /dev/null +++ b/internal/gtsmodel/followrequest_test.go @@ -0,0 +1,87 @@ +/* +   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 gtsmodel_test + +import ( +	"testing" +	"time" + +	"github.com/stretchr/testify/suite" +	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +func happyFollowRequest() *gtsmodel.FollowRequest { +	return >smodel.FollowRequest{ +		ID:              "01FE91RJR88PSEEE30EV35QR8N", +		CreatedAt:       time.Now(), +		UpdatedAt:       time.Now(), +		AccountID:       "01FE96MAE58MXCE5C4SSMEMCEK", +		Account:         nil, +		TargetAccountID: "01FE96MXRHWZHKC0WH5FT82H1A", +		TargetAccount:   nil, +		URI:             "https://example.org/users/user1/activity/follow/01FE91RJR88PSEEE30EV35QR8N", +	} +} + +type FollowRequestValidateTestSuite struct { +	suite.Suite +} + +func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestHappyPath() { +	// no problem here +	f := happyFollowRequest() +	err := gtsmodel.ValidateStruct(*f) +	suite.NoError(err) +} + +func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestBadID() { +	f := happyFollowRequest() + +	f.ID = "" +	err := gtsmodel.ValidateStruct(*f) +	suite.EqualError(err, "Key: 'FollowRequest.ID' Error:Field validation for 'ID' failed on the 'required' tag") + +	f.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" +	err = gtsmodel.ValidateStruct(*f) +	suite.EqualError(err, "Key: 'FollowRequest.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") +} + +func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestNoCreatedAt() { +	f := happyFollowRequest() + +	f.CreatedAt = time.Time{} +	err := gtsmodel.ValidateStruct(*f) +	suite.NoError(err) +} + +func (suite *FollowRequestValidateTestSuite) TestValidateFollowRequestNoURI() { +	f := happyFollowRequest() + +	f.URI = "" +	err := gtsmodel.ValidateStruct(*f) +	suite.EqualError(err, "Key: 'FollowRequest.URI' Error:Field validation for 'URI' failed on the 'required' tag") + +	f.URI = "this-is-not-a-valid-url" +	err = gtsmodel.ValidateStruct(*f) +	suite.EqualError(err, "Key: 'FollowRequest.URI' Error:Field validation for 'URI' failed on the 'url' tag") +} + +func TestFollowRequestValidateTestSuite(t *testing.T) { +	suite.Run(t, new(FollowRequestValidateTestSuite)) +} diff --git a/internal/gtsmodel/instance.go b/internal/gtsmodel/instance.go index ca2857b95..4d36dbba8 100644 --- a/internal/gtsmodel/instance.go +++ b/internal/gtsmodel/instance.go @@ -4,38 +4,22 @@ import "time"  // Instance represents a federated instance, either local or remote.  type Instance struct { -	// ID of this instance in the database -	ID string `bun:"type:CHAR(26),pk,notnull,unique"` -	// Instance domain eg example.org -	Domain string `bun:",pk,notnull,unique"` -	// Title of this instance as it would like to be displayed. -	Title string `bun:",nullzero"` -	// base URI of this instance eg https://example.org -	URI string `bun:",notnull,unique"` -	// When was this instance created in the db? -	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// When was this instance last updated in the db? -	UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"` -	// When was this instance suspended, if at all? -	SuspendedAt time.Time `bun:",nullzero"` -	// ID of any existing domain block for this instance in the database -	DomainBlockID string       `bun:"type:CHAR(26),nullzero"` -	DomainBlock   *DomainBlock `bun:"rel:belongs-to"` -	// Short description of this instance -	ShortDescription string `bun:",nullzero"` -	// Longer description of this instance -	Description string `bun:",nullzero"` -	// Terms and conditions of this instance -	Terms string `bun:",nullzero"` -	// Contact email address for this instance -	ContactEmail string `bun:",nullzero"` -	// Username of the contact account for this instance -	ContactAccountUsername string `bun:",nullzero"` -	// Contact account ID in the database for this instance -	ContactAccountID string   `bun:"type:CHAR(26),nullzero"` -	ContactAccount   *Account `bun:"rel:belongs-to"` -	// Reputation score of this instance -	Reputation int64 `bun:",notnull,default:0"` -	// Version of the software used on this instance -	Version string `bun:",nullzero"` +	ID                     string       `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                     // id of this item in the database +	CreatedAt              time.Time    `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`                              // when was item created +	UpdatedAt              time.Time    `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`                              // when was item last updated +	Domain                 string       `validate:"required,fqdn" bun:",nullzero,notnull,unique"`                                     // Instance domain eg example.org +	Title                  string       `validate:"-" bun:",nullzero"`                                                                // Title of this instance as it would like to be displayed. +	URI                    string       `validate:"required,url" bun:",nullzero,notnull,unique"`                                      // base URI of this instance eg https://example.org +	SuspendedAt            time.Time    `validate:"-" bun:",nullzero"`                                                                // When was this instance suspended, if at all? +	DomainBlockID          string       `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"`                                      // ID of any existing domain block for this instance in the database +	DomainBlock            *DomainBlock `validate:"-" bun:"rel:belongs-to"`                                                           // Domain block corresponding to domainBlockID +	ShortDescription       string       `validate:"-" bun:",nullzero"`                                                                // Short description of this instance +	Description            string       `validate:"-" bun:",nullzero"`                                                                // Longer description of this instance +	Terms                  string       `validate:"-" bun:",nullzero"`                                                                // Terms and conditions of this instance +	ContactEmail           string       `validate:"omitempty,email" bun:",nullzero"`                                                  // Contact email address for this instance +	ContactAccountUsername string       `validate:"required_with=ContactAccountID" bun:",nullzero"`                                   // Username of the contact account for this instance +	ContactAccountID       string       `validate:"required_with=ContactAccountUsername,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Contact account ID in the database for this instance +	ContactAccount         *Account     `validate:"-" bun:"rel:belongs-to"`                                                           // account corresponding to contactAccountID +	Reputation             int64        `validate:"-" bun:",notnull,default:0"`                                                       // Reputation score of this instance +	Version                string       `validate:"-" bun:",nullzero"`                                                                // Version of the software used on this instance  } diff --git a/internal/gtsmodel/instance_test.go b/internal/gtsmodel/instance_test.go new file mode 100644 index 000000000..5c685bb25 --- /dev/null +++ b/internal/gtsmodel/instance_test.go @@ -0,0 +1,145 @@ +/* +   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 gtsmodel_test + +import ( +	"testing" +	"time" + +	"github.com/stretchr/testify/suite" +	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +) + +func happyInstance() *gtsmodel.Instance { +	return >smodel.Instance{ +		ID:                     "01FE91RJR88PSEEE30EV35QR8N", +		CreatedAt:              time.Now(), +		UpdatedAt:              time.Now(), +		Domain:                 "example.org", +		Title:                  "Example Instance", +		URI:                    "https://example.org", +		SuspendedAt:            time.Time{}, +		DomainBlockID:          "", +		DomainBlock:            nil, +		ShortDescription:       "This is a description for the example/testing instance.", +		Description:            "This is a way longer description for the example/testing instance!", +		Terms:                  "Don't be a knobhead.", +		ContactEmail:           "admin@example.org", +		ContactAccountUsername: "admin", +		ContactAccountID:       "01FEE20H5QWHJDEXAEE9G96PR0", +		ContactAccount:         nil, +		Reputation:             420, +		Version:                "gotosocial 0.1.0", +	} +} + +type InstanceValidateTestSuite struct { +	suite.Suite +} + +func (suite *InstanceValidateTestSuite) TestValidateInstanceHappyPath() { +	// no problem here +	m := happyInstance() +	err := gtsmodel.ValidateStruct(*m) +	suite.NoError(err) +} + +func (suite *InstanceValidateTestSuite) TestValidateInstanceBadID() { +	m := happyInstance() + +	m.ID = "" +	err := gtsmodel.ValidateStruct(*m) +	suite.EqualError(err, "Key: 'Instance.ID' Error:Field validation for 'ID' failed on the 'required' tag") + +	m.ID = "01FE96W293ZPRG9FQQP48HK8N001FE96W32AT24VYBGM12WN3GKB" +	err = gtsmodel.ValidateStruct(*m) +	suite.EqualError(err, "Key: 'Instance.ID' Error:Field validation for 'ID' failed on the 'ulid' tag") +} + +func (suite *InstanceValidateTestSuite) TestValidateInstanceAccountURI() { +	i := happyInstance() + +	i.URI = "" +	err := gtsmodel.ValidateStruct(*i) +	suite.EqualError(err, "Key: 'Instance.URI' Error:Field validation for 'URI' failed on the 'required' tag") + +	i.URI = "---------------------------" +	err = gtsmodel.ValidateStruct(*i) +	suite.EqualError(err, "Key: 'Instance.URI' Error:Field validation for 'URI' failed on the 'url' tag") +} + +func (suite *InstanceValidateTestSuite) TestValidateInstanceDodgyAccountID() { +	i := happyInstance() + +	i.ContactAccountID = "9HZJ76B6VXSKF" +	err := gtsmodel.ValidateStruct(*i) +	suite.EqualError(err, "Key: 'Instance.ContactAccountID' Error:Field validation for 'ContactAccountID' failed on the 'ulid' tag") + +	i.ContactAccountID = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!!!!!!!!!!!!" +	err = gtsmodel.ValidateStruct(*i) +	suite.EqualError(err, "Key: 'Instance.ContactAccountID' Error:Field validation for 'ContactAccountID' failed on the 'ulid' tag") + +	i.ContactAccountID = "" +	err = gtsmodel.ValidateStruct(*i) +	suite.EqualError(err, "Key: 'Instance.ContactAccountID' Error:Field validation for 'ContactAccountID' failed on the 'required_with' tag") + +	i.ContactAccountUsername = "" +	err = gtsmodel.ValidateStruct(*i) +	suite.NoError(err) +} + +func (suite *InstanceValidateTestSuite) TestValidateInstanceDomain() { +	i := happyInstance() + +	i.Domain = "poopoo" +	err := gtsmodel.ValidateStruct(*i) +	suite.EqualError(err, "Key: 'Instance.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") + +	i.Domain = "" +	err = gtsmodel.ValidateStruct(*i) +	suite.EqualError(err, "Key: 'Instance.Domain' Error:Field validation for 'Domain' failed on the 'required' tag") + +	i.Domain = "https://aaaaaaaaaaaaah.org" +	err = gtsmodel.ValidateStruct(*i) +	suite.EqualError(err, "Key: 'Instance.Domain' Error:Field validation for 'Domain' failed on the 'fqdn' tag") +} + +func (suite *InstanceValidateTestSuite) TestValidateInstanceContactEmail() { +	i := happyInstance() + +	i.ContactEmail = "poopoo" +	err := gtsmodel.ValidateStruct(*i) +	suite.EqualError(err, "Key: 'Instance.ContactEmail' Error:Field validation for 'ContactEmail' failed on the 'email' tag") + +	i.ContactEmail = "" +	err = gtsmodel.ValidateStruct(*i) +	suite.NoError(err) +} + +func (suite *InstanceValidateTestSuite) TestValidateInstanceNoCreatedAt() { +	i := happyInstance() + +	i.CreatedAt = time.Time{} +	err := gtsmodel.ValidateStruct(*i) +	suite.NoError(err) +} + +func TestInstanceValidateTestSuite(t *testing.T) { +	suite.Run(t, new(InstanceValidateTestSuite)) +} diff --git a/internal/gtsmodel/mediaattachment.go b/internal/gtsmodel/mediaattachment.go index 5d7bd8e17..53f226ad7 100644 --- a/internal/gtsmodel/mediaattachment.go +++ b/internal/gtsmodel/mediaattachment.go @@ -26,8 +26,8 @@ import (  // somewhere in storage and that can be retrieved and served by the router.  type MediaAttachment struct {  	ID                string           `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                       // id of this item in the database -	CreatedAt         time.Time        `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`                         // when was item created -	UpdatedAt         time.Time        `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`                         // when was item last updated +	CreatedAt         time.Time        `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`                                // when was item created +	UpdatedAt         time.Time        `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`                                // when was item last updated  	StatusID          string           `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"`                                        // ID of the status to which this is attached  	URL               string           `validate:"required_without=RemoteURL,omitempty,url" bun:",nullzero"`                           // Where can the attachment be retrieved on *this* server  	RemoteURL         string           `validate:"required_without=URL,omitempty,url" bun:",nullzero"`                                 // Where can the attachment be retrieved on a remote server (empty for local media) @@ -47,25 +47,26 @@ type MediaAttachment struct {  // File refers to the metadata for the whole file  type File struct { -	Path        string    `validate:"required,file" bun:",nullzero,notnull"`                      // Path of the file in storage. -	ContentType string    `validate:"required" bun:",nullzero,notnull"`                           // MIME content type of the file. -	FileSize    int       `validate:"required" bun:",nullzero,notnull"`                           // File size in bytes -	UpdatedAt   time.Time `validate:"required" bun:",nullzero,notnull,default:current_timestamp"` // When was the file last updated. +	Path        string    `validate:"required,file" bun:",nullzero,notnull"`               // Path of the file in storage. +	ContentType string    `validate:"required" bun:",nullzero,notnull"`                    // MIME content type of the file. +	FileSize    int       `validate:"required" bun:",nullzero,notnull"`                    // File size in bytes +	UpdatedAt   time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"` // When was the file last updated.  }  // Thumbnail refers to a small image thumbnail derived from a larger image, video, or audio file.  type Thumbnail struct { -	Path        string    `validate:"required,file" bun:",nullzero,notnull"`                      // Path of the file in storage. -	ContentType string    `validate:"required" bun:",nullzero,notnull"`                           // MIME content type of the file. -	FileSize    int       `validate:"required" bun:",nullzero,notnull"`                           // File size in bytes -	UpdatedAt   time.Time `validate:"required" bun:",nullzero,notnull,default:current_timestamp"` // When was the file last updated. -	URL         string    `validate:"required_without=RemoteURL,omitempty,url" bun:",nullzero"`   // What is the URL of the thumbnail on the local server -	RemoteURL   string    `validate:"required_without=URL,omitempty,url" bun:",nullzero"`         // What is the remote URL of the thumbnail (empty for local media) +	Path        string    `validate:"required,file" bun:",nullzero,notnull"`                    // Path of the file in storage. +	ContentType string    `validate:"required" bun:",nullzero,notnull"`                         // MIME content type of the file. +	FileSize    int       `validate:"required" bun:",nullzero,notnull"`                         // File size in bytes +	UpdatedAt   time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`      // When was the file last updated. +	URL         string    `validate:"required_without=RemoteURL,omitempty,url" bun:",nullzero"` // What is the URL of the thumbnail on the local server +	RemoteURL   string    `validate:"required_without=URL,omitempty,url" bun:",nullzero"`       // What is the remote URL of the thumbnail (empty for local media)  }  // ProcessingStatus refers to how far along in the processing stage the attachment is.  type ProcessingStatus int +// MediaAttachment processing states.  const (  	ProcessingStatusReceived   ProcessingStatus = 0   // ProcessingStatusReceived indicates the attachment has been received and is awaiting processing. No thumbnail available yet.  	ProcessingStatusProcessing ProcessingStatus = 1   // ProcessingStatusProcessing indicates the attachment is currently being processed. Thumbnail is available but full media is not. @@ -76,6 +77,7 @@ const (  // FileType refers to the file type of the media attaachment.  type FileType string +// MediaAttachment file types.  const (  	FileTypeImage   FileType = "Image"   // FileTypeImage is for jpegs and pngs  	FileTypeGif     FileType = "Gif"     // FileTypeGif is for native gifs and soundless videos that have been converted to gifs diff --git a/internal/gtsmodel/mediaattachment_test.go b/internal/gtsmodel/mediaattachment_test.go index e95d07de4..e1502ba62 100644 --- a/internal/gtsmodel/mediaattachment_test.go +++ b/internal/gtsmodel/mediaattachment_test.go @@ -212,6 +212,18 @@ func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentBlurha  	suite.NoError(err)  } +func (suite *MediaAttachmentValidateTestSuite) TestValidateMediaAttachmentProcessing() { +	m := happyMediaAttachment() + +	m.Processing = 420 +	err := gtsmodel.ValidateStruct(*m) +	suite.EqualError(err, "Key: 'MediaAttachment.Processing' Error:Field validation for 'Processing' failed on the 'oneof' tag") + +	m.Processing = -5 +	err = gtsmodel.ValidateStruct(*m) +	suite.EqualError(err, "Key: 'MediaAttachment.Processing' Error:Field validation for 'Processing' failed on the 'oneof' tag") +} +  func TestMediaAttachmentValidateTestSuite(t *testing.T) {  	suite.Run(t, new(MediaAttachmentValidateTestSuite))  } diff --git a/internal/gtsmodel/mention.go b/internal/gtsmodel/mention.go index de85b364b..d8359745d 100644 --- a/internal/gtsmodel/mention.go +++ b/internal/gtsmodel/mention.go @@ -23,8 +23,8 @@ import "time"  // Mention refers to the 'tagging' or 'mention' of a user within a status.  type Mention struct {  	ID               string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database -	CreatedAt        time.Time `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`   // when was item created -	UpdatedAt        time.Time `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`   // when was item last updated +	CreatedAt        time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created +	UpdatedAt        time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item last updated  	StatusID         string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`           // ID of the status this mention originates from  	Status           *Status   `validate:"-" bun:"rel:belongs-to"`                                       // status referred to by statusID  	OriginAccountID  string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`           // ID of the mention creator account diff --git a/internal/gtsmodel/mention_test.go b/internal/gtsmodel/mention_test.go index de8eae835..ac44e916b 100644 --- a/internal/gtsmodel/mention_test.go +++ b/internal/gtsmodel/mention_test.go @@ -93,7 +93,7 @@ func (suite *MentionValidateTestSuite) TestValidateMentionNoCreatedAt() {  	m.CreatedAt = time.Time{}  	err := gtsmodel.ValidateStruct(*m) -	suite.EqualError(err, "Key: 'Mention.CreatedAt' Error:Field validation for 'CreatedAt' failed on the 'required' tag") +	suite.NoError(err)  }  func TestMentionValidateTestSuite(t *testing.T) { diff --git a/internal/gtsmodel/notification.go b/internal/gtsmodel/notification.go index 94eaa8c4a..bb69bc8d4 100644 --- a/internal/gtsmodel/notification.go +++ b/internal/gtsmodel/notification.go @@ -23,7 +23,7 @@ import "time"  // Notification models an alert/notification sent to an account about something like a reblog, like, new follow request, etc.  type Notification struct {  	ID               string           `validate:"ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                                                                                                                                             // id of this item in the database -	CreatedAt        time.Time        `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`                                                                                                                                      // when was item created +	CreatedAt        time.Time        `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`                                                                                                                                             // when was item created  	NotificationType NotificationType `validate:"oneof=follow follow_request mention reblog favourite poll status" bun:",nullzero,notnull"`                                                                                                        // Type of this notification  	TargetAccountID  string           `validate:"ulid" bun:"type:CHAR(26),nullzero,notnull"`                                                                                                                                                       // Which account does this notification target (ie., who will receive the notification?)  	TargetAccount    *Account         `validate:"-" bun:"rel:belongs-to"`                                                                                                                                                                          // Which account performed the action that created this notification? @@ -37,6 +37,7 @@ type Notification struct {  // NotificationType describes the reason/type of this notification.  type NotificationType string +// Notification Types  const (  	NotificationFollow        NotificationType = "follow"         // NotificationFollow -- someone followed you  	NotificationFollowRequest NotificationType = "follow_request" // NotificationFollowRequest -- someone requested to follow you diff --git a/internal/gtsmodel/notification_test.go b/internal/gtsmodel/notification_test.go index 29da2f269..507a2cbfd 100644 --- a/internal/gtsmodel/notification_test.go +++ b/internal/gtsmodel/notification_test.go @@ -89,7 +89,7 @@ func (suite *NotificationValidateTestSuite) TestValidateNotificationNoCreatedAt(  	m.CreatedAt = time.Time{}  	err := gtsmodel.ValidateStruct(*m) -	suite.EqualError(err, "Key: 'Notification.CreatedAt' Error:Field validation for 'CreatedAt' failed on the 'required' tag") +	suite.NoError(err)  }  func TestNotificationValidateTestSuite(t *testing.T) { diff --git a/internal/gtsmodel/relationship.go b/internal/gtsmodel/relationship.go index 4e6cc03f6..3f753f6e9 100644 --- a/internal/gtsmodel/relationship.go +++ b/internal/gtsmodel/relationship.go @@ -20,30 +20,17 @@ package gtsmodel  // Relationship describes a requester's relationship with another account.  type Relationship struct { -	// The account id. -	ID string -	// Are you following this user? -	Following bool -	// Are you receiving this user's boosts in your home timeline? -	ShowingReblogs bool -	// Have you enabled notifications for this user? -	Notifying bool -	// Are you followed by this user? -	FollowedBy bool -	// Are you blocking this user? -	Blocking bool -	// Is this user blocking you? -	BlockedBy bool -	// Are you muting this user? -	Muting bool -	// Are you muting notifications from this user? -	MutingNotifications bool -	// Do you have a pending follow request for this user? -	Requested bool -	// Are you blocking this user's domain? -	DomainBlocking bool -	// Are you featuring this user on your profile? -	Endorsed bool -	// Your note on this account. -	Note string +	ID                  string // The account id. +	Following           bool   // Are you following this user? +	ShowingReblogs      bool   // Are you receiving this user's boosts in your home timeline? +	Notifying           bool   // Have you enabled notifications for this user? +	FollowedBy          bool   // Are you followed by this user? +	Blocking            bool   // Are you blocking this user? +	BlockedBy           bool   // Is this user blocking you? +	Muting              bool   // Are you muting this user? +	MutingNotifications bool   // Are you muting notifications from this user? +	Requested           bool   // Do you have a pending follow request for this user? +	DomainBlocking      bool   // Are you blocking this user's domain? +	Endorsed            bool   // Are you featuring this user on your profile? +	Note                string // Your note on this account.  } diff --git a/internal/gtsmodel/status.go b/internal/gtsmodel/status.go index eca9262c6..d81a45ec3 100644 --- a/internal/gtsmodel/status.go +++ b/internal/gtsmodel/status.go @@ -25,8 +25,8 @@ import (  // Status represents a user-created 'post' or 'status' in the database, either remote or local  type Status struct {  	ID                       string             `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"`                              // id of this item in the database -	CreatedAt                time.Time          `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`                                // when was item created -	UpdatedAt                time.Time          `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`                                // when was item last updated +	CreatedAt                time.Time          `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`                                       // when was item created +	UpdatedAt                time.Time          `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`                                       // when was item last updated  	URI                      string             `validate:"required,url" bun:",unique,nullzero,notnull"`                                               // activitypub URI of this status  	URL                      string             `validate:"url" bun:",nullzero"`                                                                       // web url for viewing this status  	Content                  string             `validate:"-" bun:",nullzero"`                                                                         // content of this status; likely html-formatted but not guaranteed diff --git a/internal/gtsmodel/status_test.go b/internal/gtsmodel/status_test.go index 1d934b891..7f3b2f38f 100644 --- a/internal/gtsmodel/status_test.go +++ b/internal/gtsmodel/status_test.go @@ -23,6 +23,7 @@ import (  	"time"  	"github.com/stretchr/testify/suite" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  ) @@ -67,7 +68,7 @@ func happyStatus() *gtsmodel.Status {  			Replyable: true,  			Likeable:  true,  		}, -		ActivityStreamsType: gtsmodel.ActivityStreamsNote, +		ActivityStreamsType: ap.ObjectNote,  		Text:                "Test status! #hello",  		Pinned:              false,  	} diff --git a/internal/gtsmodel/statusbookmark.go b/internal/gtsmodel/statusbookmark.go index cabf90c06..76a2a866d 100644 --- a/internal/gtsmodel/statusbookmark.go +++ b/internal/gtsmodel/statusbookmark.go @@ -23,7 +23,7 @@ import "time"  // StatusBookmark refers to one account having a 'bookmark' of the status of another account.  type StatusBookmark struct {  	ID              string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database -	CreatedAt       time.Time `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`   // when was item created +	CreatedAt       time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created  	AccountID       string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`           // id of the account that created ('did') the bookmark  	Account         *Account  `validate:"-" bun:"rel:belongs-to"`                                       // account that created the bookmark  	TargetAccountID string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`           // id the account owning the bookmarked status diff --git a/internal/gtsmodel/statusbookmark_test.go b/internal/gtsmodel/statusbookmark_test.go index 7acd77698..e7a67fc35 100644 --- a/internal/gtsmodel/statusbookmark_test.go +++ b/internal/gtsmodel/statusbookmark_test.go @@ -79,7 +79,7 @@ func (suite *StatusBookmarkValidateTestSuite) TestValidateStatusBookmarkNoCreate  	m.CreatedAt = time.Time{}  	err := gtsmodel.ValidateStruct(*m) -	suite.EqualError(err, "Key: 'StatusBookmark.CreatedAt' Error:Field validation for 'CreatedAt' failed on the 'required' tag") +	suite.NoError(err)  }  func TestStatusBookmarkValidateTestSuite(t *testing.T) { diff --git a/internal/gtsmodel/statusfave.go b/internal/gtsmodel/statusfave.go index 697112aba..6647e941a 100644 --- a/internal/gtsmodel/statusfave.go +++ b/internal/gtsmodel/statusfave.go @@ -23,7 +23,7 @@ import "time"  // StatusFave refers to a 'fave' or 'like' in the database, from one account, targeting the status of another account  type StatusFave struct {  	ID              string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database -	CreatedAt       time.Time `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`   // when was item created +	CreatedAt       time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created  	AccountID       string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`           // id of the account that created ('did') the fave  	Account         *Account  `validate:"-" bun:"rel:belongs-to"`                                       // account that created the fave  	TargetAccountID string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`           // id the account owning the faved status diff --git a/internal/gtsmodel/statusfave_test.go b/internal/gtsmodel/statusfave_test.go index 65443b9fd..37f555a7c 100644 --- a/internal/gtsmodel/statusfave_test.go +++ b/internal/gtsmodel/statusfave_test.go @@ -80,7 +80,7 @@ func (suite *StatusFaveValidateTestSuite) TestValidateStatusFaveNoCreatedAt() {  	f.CreatedAt = time.Time{}  	err := gtsmodel.ValidateStruct(*f) -	suite.EqualError(err, "Key: 'StatusFave.CreatedAt' Error:Field validation for 'CreatedAt' failed on the 'required' tag") +	suite.NoError(err)  }  func (suite *StatusFaveValidateTestSuite) TestValidateStatusFaveNoURI() { diff --git a/internal/gtsmodel/statusmute.go b/internal/gtsmodel/statusmute.go index 90eb41bdb..70789e557 100644 --- a/internal/gtsmodel/statusmute.go +++ b/internal/gtsmodel/statusmute.go @@ -23,7 +23,7 @@ import "time"  // StatusMute refers to one account having muted the status of another account or its own.  type StatusMute struct {  	ID              string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database -	CreatedAt       time.Time `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`   // when was item created +	CreatedAt       time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created  	AccountID       string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`           // id of the account that created ('did') the mute  	Account         *Account  `validate:"-" bun:"rel:belongs-to"`                                       // pointer to the account specified by accountID  	TargetAccountID string    `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"`           // id the account owning the muted status (can be the same as accountID) diff --git a/internal/gtsmodel/statusmute_test.go b/internal/gtsmodel/statusmute_test.go index 294422086..b3926bb69 100644 --- a/internal/gtsmodel/statusmute_test.go +++ b/internal/gtsmodel/statusmute_test.go @@ -79,7 +79,7 @@ func (suite *StatusMuteValidateTestSuite) TestValidateStatusMuteNoCreatedAt() {  	m.CreatedAt = time.Time{}  	err := gtsmodel.ValidateStruct(*m) -	suite.EqualError(err, "Key: 'StatusMute.CreatedAt' Error:Field validation for 'CreatedAt' failed on the 'required' tag") +	suite.NoError(err)  }  func TestStatusMuteValidateTestSuite(t *testing.T) { diff --git a/internal/gtsmodel/tag.go b/internal/gtsmodel/tag.go index f6029e943..14ff26f87 100644 --- a/internal/gtsmodel/tag.go +++ b/internal/gtsmodel/tag.go @@ -23,12 +23,12 @@ import "time"  // Tag represents a hashtag for gathering public statuses together.  type Tag struct {  	ID                     string    `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database -	CreatedAt              time.Time `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`   // when was item created -	UpdatedAt              time.Time `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`   // when was item last updated -	URL                    string    `validate:"required,url" bun:",nullzero,notnull"`                         // Href of this tag, eg https://example.org/tags/somehashtag +	CreatedAt              time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created +	UpdatedAt              time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item last updated +	URL                    string    `validate:"required,url" bun:",nullzero,notnull"`                         // Href/web address of this tag, eg https://example.org/tags/somehashtag  	Name                   string    `validate:"required" bun:",unique,nullzero,notnull"`                      // name of this tag -- the tag without the hash part  	FirstSeenFromAccountID string    `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"`                  // Which account ID is the first one we saw using this tag?  	Useable                bool      `validate:"-" bun:",notnull,default:true"`                                // can our instance users use this tag?  	Listable               bool      `validate:"-" bun:",notnull,default:true"`                                // can our instance users look up this tag? -	LastStatusAt           time.Time `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`   // when was this tag last used? +	LastStatusAt           time.Time `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was this tag last used?  } diff --git a/internal/gtsmodel/user.go b/internal/gtsmodel/user.go index 85912d32b..e0568d6a0 100644 --- a/internal/gtsmodel/user.go +++ b/internal/gtsmodel/user.go @@ -27,8 +27,8 @@ import (  // To cross reference this local user with their account (which can be local or remote), use the AccountID field.  type User struct {  	ID                     string       `validate:"required,ulid" bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database -	CreatedAt              time.Time    `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`   // when was item created -	UpdatedAt              time.Time    `validate:"required" bun:",nullzero,notnull,default:current_timestamp"`   // when was item last updated +	CreatedAt              time.Time    `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item created +	UpdatedAt              time.Time    `validate:"-" bun:",nullzero,notnull,default:current_timestamp"`          // when was item last updated  	Email                  string       `validate:"required_with=ConfirmedAt" bun:",nullzero,unique"`             // confirmed email address for this user, this should be unique -- only one email address registered per instance, multiple users per email are not supported  	AccountID              string       `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull,unique"`    // The id of the local gtsmodel.Account entry for this user.  	Account                *Account     `validate:"-" bun:"rel:belongs-to"`                                       // Pointer to the account of this user that corresponds to AccountID. diff --git a/internal/gtsmodel/validate.go b/internal/gtsmodel/validate.go index da9f6d3eb..0e1957b28 100644 --- a/internal/gtsmodel/validate.go +++ b/internal/gtsmodel/validate.go @@ -27,6 +27,7 @@ import (  var v *validator.Validate +// Validation Panic messages  const (  	PointerValidationPanic = "validate function was passed pointer"  	InvalidValidationPanic = "validate function was passed invalid item" @@ -48,6 +49,7 @@ func init() {  	v.RegisterValidation("ulid", ulidValidator)  } +// ValidateStruct validates the passed struct, returning validator.ValidationErrors if invalid, or nil if OK.  func ValidateStruct(s interface{}) error {  	switch reflect.ValueOf(s).Kind() {  	case reflect.Invalid: diff --git a/internal/id/ulid.go b/internal/id/ulid.go index f9fbd4d88..1b0c2e537 100644 --- a/internal/id/ulid.go +++ b/internal/id/ulid.go @@ -10,6 +10,7 @@ import (  const randomRange = 631152381 // ~20 years in seconds +// ULID represents a Universally Unique Lexicographically Sortable Identifier of 26 characters. See https://github.com/oklog/ulid  type ULID string  // NewULID returns a new ULID string using the current time, or an error if something goes wrong. diff --git a/internal/gtsmodel/messages.go b/internal/messages/messages.go index 62beb0adc..6cd2f466c 100644 --- a/internal/gtsmodel/messages.go +++ b/internal/messages/messages.go @@ -16,21 +16,23 @@     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ -package gtsmodel +package messages -// FromClientAPI wraps a message that travels from client API into the processor +import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + +// FromClientAPI wraps a message that travels from the client API into the processor.  type FromClientAPI struct {  	APObjectType   string  	APActivityType string  	GTSModel       interface{} -	OriginAccount  *Account -	TargetAccount  *Account +	OriginAccount  *gtsmodel.Account +	TargetAccount  *gtsmodel.Account  } -// FromFederator wraps a message that travels from the federator into the processor +// FromFederator wraps a message that travels from the federator into the processor.  type FromFederator struct {  	APObjectType     string  	APActivityType   string  	GTSModel         interface{} -	ReceivingAccount *Account +	ReceivingAccount *gtsmodel.Account  } diff --git a/internal/processing/account/account.go b/internal/processing/account/account.go index 81701fd7c..71b876d3b 100644 --- a/internal/processing/account/account.go +++ b/internal/processing/account/account.go @@ -30,6 +30,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/media" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/oauth"  	"github.com/superseriousbusiness/gotosocial/internal/typeutils"  	"github.com/superseriousbusiness/gotosocial/internal/visibility" @@ -79,7 +80,7 @@ type processor struct {  	tc            typeutils.TypeConverter  	config        *config.Config  	mediaHandler  media.Handler -	fromClientAPI chan gtsmodel.FromClientAPI +	fromClientAPI chan messages.FromClientAPI  	oauthServer   oauth.Server  	filter        visibility.Filter  	db            db.DB @@ -88,7 +89,7 @@ type processor struct {  }  // New returns a new account processor. -func New(db db.DB, tc typeutils.TypeConverter, mediaHandler media.Handler, oauthServer oauth.Server, fromClientAPI chan gtsmodel.FromClientAPI, federator federation.Federator, config *config.Config, log *logrus.Logger) Processor { +func New(db db.DB, tc typeutils.TypeConverter, mediaHandler media.Handler, oauthServer oauth.Server, fromClientAPI chan messages.FromClientAPI, federator federation.Federator, config *config.Config, log *logrus.Logger) Processor {  	return &processor{  		tc:            tc,  		config:        config, diff --git a/internal/processing/account/createblock.go b/internal/processing/account/createblock.go index 06f82b37d..347f19bee 100644 --- a/internal/processing/account/createblock.go +++ b/internal/processing/account/createblock.go @@ -22,11 +22,13 @@ import (  	"context"  	"fmt" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/id" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) @@ -111,9 +113,9 @@ func (p *processor) BlockCreate(ctx context.Context, requestingAccount *gtsmodel  	// follow request status changed so send the UNDO activity to the channel for async processing  	if frChanged { -		p.fromClientAPI <- gtsmodel.FromClientAPI{ -			APObjectType:   gtsmodel.ActivityStreamsFollow, -			APActivityType: gtsmodel.ActivityStreamsUndo, +		p.fromClientAPI <- messages.FromClientAPI{ +			APObjectType:   ap.ActivityFollow, +			APActivityType: ap.ActivityUndo,  			GTSModel: >smodel.Follow{  				AccountID:       requestingAccount.ID,  				TargetAccountID: targetAccountID, @@ -126,9 +128,9 @@ func (p *processor) BlockCreate(ctx context.Context, requestingAccount *gtsmodel  	// follow status changed so send the UNDO activity to the channel for async processing  	if fChanged { -		p.fromClientAPI <- gtsmodel.FromClientAPI{ -			APObjectType:   gtsmodel.ActivityStreamsFollow, -			APActivityType: gtsmodel.ActivityStreamsUndo, +		p.fromClientAPI <- messages.FromClientAPI{ +			APObjectType:   ap.ActivityFollow, +			APActivityType: ap.ActivityUndo,  			GTSModel: >smodel.Follow{  				AccountID:       requestingAccount.ID,  				TargetAccountID: targetAccountID, @@ -140,9 +142,9 @@ func (p *processor) BlockCreate(ctx context.Context, requestingAccount *gtsmodel  	}  	// handle the rest of the block process asynchronously -	p.fromClientAPI <- gtsmodel.FromClientAPI{ -		APObjectType:   gtsmodel.ActivityStreamsBlock, -		APActivityType: gtsmodel.ActivityStreamsCreate, +	p.fromClientAPI <- messages.FromClientAPI{ +		APObjectType:   ap.ActivityBlock, +		APActivityType: ap.ActivityCreate,  		GTSModel:       block,  		OriginAccount:  requestingAccount,  		TargetAccount:  targetAccount, diff --git a/internal/processing/account/createfollow.go b/internal/processing/account/createfollow.go index a7767afea..d3ca386ed 100644 --- a/internal/processing/account/createfollow.go +++ b/internal/processing/account/createfollow.go @@ -22,11 +22,13 @@ import (  	"context"  	"fmt" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/id" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) @@ -99,9 +101,9 @@ func (p *processor) FollowCreate(ctx context.Context, requestingAccount *gtsmode  	}  	// otherwise we leave the follow request as it is and we handle the rest of the process asynchronously -	p.fromClientAPI <- gtsmodel.FromClientAPI{ -		APObjectType:   gtsmodel.ActivityStreamsFollow, -		APActivityType: gtsmodel.ActivityStreamsCreate, +	p.fromClientAPI <- messages.FromClientAPI{ +		APObjectType:   ap.ActivityFollow, +		APActivityType: ap.ActivityCreate,  		GTSModel:       fr,  		OriginAccount:  requestingAccount,  		TargetAccount:  targetAcct, diff --git a/internal/processing/account/delete.go b/internal/processing/account/delete.go index d97af4d2e..318f4f1e5 100644 --- a/internal/processing/account/delete.go +++ b/internal/processing/account/delete.go @@ -23,8 +23,10 @@ import (  	"time"  	"github.com/sirupsen/logrus" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/oauth"  ) @@ -150,9 +152,9 @@ selectStatusesLoop:  			// pass the status delete through the client api channel for processing  			s.Account = account  			l.Debug("putting status in the client api channel") -			p.fromClientAPI <- gtsmodel.FromClientAPI{ -				APObjectType:   gtsmodel.ActivityStreamsNote, -				APActivityType: gtsmodel.ActivityStreamsDelete, +			p.fromClientAPI <- messages.FromClientAPI{ +				APObjectType:   ap.ObjectNote, +				APActivityType: ap.ActivityDelete,  				GTSModel:       s,  				OriginAccount:  account,  				TargetAccount:  account, @@ -186,9 +188,9 @@ selectStatusesLoop:  				}  				l.Debug("putting boost undo in the client api channel") -				p.fromClientAPI <- gtsmodel.FromClientAPI{ -					APObjectType:   gtsmodel.ActivityStreamsAnnounce, -					APActivityType: gtsmodel.ActivityStreamsUndo, +				p.fromClientAPI <- messages.FromClientAPI{ +					APObjectType:   ap.ActivityAnnounce, +					APActivityType: ap.ActivityUndo,  					GTSModel:       s,  					OriginAccount:  b.Account,  					TargetAccount:  account, diff --git a/internal/processing/account/removeblock.go b/internal/processing/account/removeblock.go index 7e3d78076..06bafb3a4 100644 --- a/internal/processing/account/removeblock.go +++ b/internal/processing/account/removeblock.go @@ -22,10 +22,12 @@ import (  	"context"  	"fmt" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  )  func (p *processor) BlockRemove(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { @@ -52,9 +54,9 @@ func (p *processor) BlockRemove(ctx context.Context, requestingAccount *gtsmodel  	// block status changed so send the UNDO activity to the channel for async processing  	if blockChanged { -		p.fromClientAPI <- gtsmodel.FromClientAPI{ -			APObjectType:   gtsmodel.ActivityStreamsBlock, -			APActivityType: gtsmodel.ActivityStreamsUndo, +		p.fromClientAPI <- messages.FromClientAPI{ +			APObjectType:   ap.ActivityBlock, +			APActivityType: ap.ActivityUndo,  			GTSModel:       block,  			OriginAccount:  requestingAccount,  			TargetAccount:  targetAccount, diff --git a/internal/processing/account/removefollow.go b/internal/processing/account/removefollow.go index 6186c550f..9791f2e54 100644 --- a/internal/processing/account/removefollow.go +++ b/internal/processing/account/removefollow.go @@ -22,10 +22,12 @@ import (  	"context"  	"fmt" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  )  func (p *processor) FollowRemove(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { @@ -78,9 +80,9 @@ func (p *processor) FollowRemove(ctx context.Context, requestingAccount *gtsmode  	// follow request status changed so send the UNDO activity to the channel for async processing  	if frChanged { -		p.fromClientAPI <- gtsmodel.FromClientAPI{ -			APObjectType:   gtsmodel.ActivityStreamsFollow, -			APActivityType: gtsmodel.ActivityStreamsUndo, +		p.fromClientAPI <- messages.FromClientAPI{ +			APObjectType:   ap.ActivityFollow, +			APActivityType: ap.ActivityUndo,  			GTSModel: >smodel.Follow{  				AccountID:       requestingAccount.ID,  				TargetAccountID: targetAccountID, @@ -93,9 +95,9 @@ func (p *processor) FollowRemove(ctx context.Context, requestingAccount *gtsmode  	// follow status changed so send the UNDO activity to the channel for async processing  	if fChanged { -		p.fromClientAPI <- gtsmodel.FromClientAPI{ -			APObjectType:   gtsmodel.ActivityStreamsFollow, -			APActivityType: gtsmodel.ActivityStreamsUndo, +		p.fromClientAPI <- messages.FromClientAPI{ +			APObjectType:   ap.ActivityFollow, +			APActivityType: ap.ActivityUndo,  			GTSModel: >smodel.Follow{  				AccountID:       requestingAccount.ID,  				TargetAccountID: targetAccountID, diff --git a/internal/processing/account/update.go b/internal/processing/account/update.go index 99ccbf5a0..5cc95b71f 100644 --- a/internal/processing/account/update.go +++ b/internal/processing/account/update.go @@ -26,9 +26,11 @@ import (  	"io"  	"mime/multipart" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/media" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/text"  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) @@ -122,9 +124,9 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form  		return nil, fmt.Errorf("could not fetch updated account %s: %s", account.ID, err)  	} -	p.fromClientAPI <- gtsmodel.FromClientAPI{ -		APObjectType:   gtsmodel.ActivityStreamsProfile, -		APActivityType: gtsmodel.ActivityStreamsUpdate, +	p.fromClientAPI <- messages.FromClientAPI{ +		APObjectType:   ap.ObjectProfile, +		APActivityType: ap.ActivityUpdate,  		GTSModel:       updatedAccount,  		OriginAccount:  updatedAccount,  	} diff --git a/internal/processing/admin/admin.go b/internal/processing/admin/admin.go index de288811b..92f69f06b 100644 --- a/internal/processing/admin/admin.go +++ b/internal/processing/admin/admin.go @@ -29,6 +29,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/media" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/typeutils"  ) @@ -46,13 +47,13 @@ type processor struct {  	tc            typeutils.TypeConverter  	config        *config.Config  	mediaHandler  media.Handler -	fromClientAPI chan gtsmodel.FromClientAPI +	fromClientAPI chan messages.FromClientAPI  	db            db.DB  	log           *logrus.Logger  }  // New returns a new admin processor. -func New(db db.DB, tc typeutils.TypeConverter, mediaHandler media.Handler, fromClientAPI chan gtsmodel.FromClientAPI, config *config.Config, log *logrus.Logger) Processor { +func New(db db.DB, tc typeutils.TypeConverter, mediaHandler media.Handler, fromClientAPI chan messages.FromClientAPI, config *config.Config, log *logrus.Logger) Processor {  	return &processor{  		tc:            tc,  		config:        config, diff --git a/internal/processing/admin/createdomainblock.go b/internal/processing/admin/createdomainblock.go index a34c03a44..9c4ff780f 100644 --- a/internal/processing/admin/createdomainblock.go +++ b/internal/processing/admin/createdomainblock.go @@ -24,11 +24,13 @@ import (  	"time"  	"github.com/sirupsen/logrus" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/id" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/text"  ) @@ -140,9 +142,9 @@ selectAccountsLoop:  			l.Debugf("putting delete for account %s in the clientAPI channel", a.Username)  			// pass the account delete through the client api channel for processing -			p.fromClientAPI <- gtsmodel.FromClientAPI{ -				APObjectType:   gtsmodel.ActivityStreamsPerson, -				APActivityType: gtsmodel.ActivityStreamsDelete, +			p.fromClientAPI <- messages.FromClientAPI{ +				APObjectType:   ap.ActorPerson, +				APActivityType: ap.ActivityDelete,  				GTSModel:       block,  				OriginAccount:  account,  				TargetAccount:  a, diff --git a/internal/processing/followrequest.go b/internal/processing/followrequest.go index 3dd6432e2..b313e42f8 100644 --- a/internal/processing/followrequest.go +++ b/internal/processing/followrequest.go @@ -21,10 +21,11 @@ package processing  import (  	"context" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror" -	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/oauth"  ) @@ -77,9 +78,9 @@ func (p *processor) FollowRequestAccept(ctx context.Context, auth *oauth.Auth, a  		follow.TargetAccount = followTargetAccount  	} -	p.fromClientAPI <- gtsmodel.FromClientAPI{ -		APObjectType:   gtsmodel.ActivityStreamsFollow, -		APActivityType: gtsmodel.ActivityStreamsAccept, +	p.fromClientAPI <- messages.FromClientAPI{ +		APObjectType:   ap.ActivityFollow, +		APActivityType: ap.ActivityAccept,  		GTSModel:       follow,  		OriginAccount:  follow.Account,  		TargetAccount:  follow.TargetAccount, diff --git a/internal/processing/fromclientapi.go b/internal/processing/fromclientapi.go index b4882ddb1..97c6cc8b2 100644 --- a/internal/processing/fromclientapi.go +++ b/internal/processing/fromclientapi.go @@ -25,16 +25,18 @@ import (  	"net/url"  	"github.com/go-fed/activity/streams" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  ) -func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel.FromClientAPI) error { +func (p *processor) processFromClientAPI(ctx context.Context, clientMsg messages.FromClientAPI) error {  	switch clientMsg.APActivityType { -	case gtsmodel.ActivityStreamsCreate: +	case ap.ActivityCreate:  		// CREATE  		switch clientMsg.APObjectType { -		case gtsmodel.ActivityStreamsNote: +		case ap.ObjectNote:  			// CREATE NOTE  			status, ok := clientMsg.GTSModel.(*gtsmodel.Status)  			if !ok { @@ -52,7 +54,7 @@ func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel  			if status.VisibilityAdvanced.Federated {  				return p.federateStatus(ctx, status)  			} -		case gtsmodel.ActivityStreamsFollow: +		case ap.ActivityFollow:  			// CREATE FOLLOW REQUEST  			followRequest, ok := clientMsg.GTSModel.(*gtsmodel.FollowRequest)  			if !ok { @@ -64,7 +66,7 @@ func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel  			}  			return p.federateFollow(ctx, followRequest, clientMsg.OriginAccount, clientMsg.TargetAccount) -		case gtsmodel.ActivityStreamsLike: +		case ap.ActivityLike:  			// CREATE LIKE/FAVE  			fave, ok := clientMsg.GTSModel.(*gtsmodel.StatusFave)  			if !ok { @@ -76,7 +78,7 @@ func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel  			}  			return p.federateFave(ctx, fave, clientMsg.OriginAccount, clientMsg.TargetAccount) -		case gtsmodel.ActivityStreamsAnnounce: +		case ap.ActivityAnnounce:  			// CREATE BOOST/ANNOUNCE  			boostWrapperStatus, ok := clientMsg.GTSModel.(*gtsmodel.Status)  			if !ok { @@ -92,7 +94,7 @@ func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel  			}  			return p.federateAnnounce(ctx, boostWrapperStatus, clientMsg.OriginAccount, clientMsg.TargetAccount) -		case gtsmodel.ActivityStreamsBlock: +		case ap.ActivityBlock:  			// CREATE BLOCK  			block, ok := clientMsg.GTSModel.(*gtsmodel.Block)  			if !ok { @@ -112,10 +114,10 @@ func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel  			return p.federateBlock(ctx, block)  		} -	case gtsmodel.ActivityStreamsUpdate: +	case ap.ActivityUpdate:  		// UPDATE  		switch clientMsg.APObjectType { -		case gtsmodel.ActivityStreamsProfile, gtsmodel.ActivityStreamsPerson: +		case ap.ObjectProfile, ap.ActorPerson:  			// UPDATE ACCOUNT/PROFILE  			account, ok := clientMsg.GTSModel.(*gtsmodel.Account)  			if !ok { @@ -124,10 +126,10 @@ func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel  			return p.federateAccountUpdate(ctx, account, clientMsg.OriginAccount)  		} -	case gtsmodel.ActivityStreamsAccept: +	case ap.ActivityAccept:  		// ACCEPT  		switch clientMsg.APObjectType { -		case gtsmodel.ActivityStreamsFollow: +		case ap.ActivityFollow:  			// ACCEPT FOLLOW  			follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow)  			if !ok { @@ -140,31 +142,31 @@ func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel  			return p.federateAcceptFollowRequest(ctx, follow, clientMsg.OriginAccount, clientMsg.TargetAccount)  		} -	case gtsmodel.ActivityStreamsUndo: +	case ap.ActivityUndo:  		// UNDO  		switch clientMsg.APObjectType { -		case gtsmodel.ActivityStreamsFollow: +		case ap.ActivityFollow:  			// UNDO FOLLOW  			follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow)  			if !ok {  				return errors.New("undo was not parseable as *gtsmodel.Follow")  			}  			return p.federateUnfollow(ctx, follow, clientMsg.OriginAccount, clientMsg.TargetAccount) -		case gtsmodel.ActivityStreamsBlock: +		case ap.ActivityBlock:  			// UNDO BLOCK  			block, ok := clientMsg.GTSModel.(*gtsmodel.Block)  			if !ok {  				return errors.New("undo was not parseable as *gtsmodel.Block")  			}  			return p.federateUnblock(ctx, block) -		case gtsmodel.ActivityStreamsLike: +		case ap.ActivityLike:  			// UNDO LIKE/FAVE  			fave, ok := clientMsg.GTSModel.(*gtsmodel.StatusFave)  			if !ok {  				return errors.New("undo was not parseable as *gtsmodel.StatusFave")  			}  			return p.federateUnfave(ctx, fave, clientMsg.OriginAccount, clientMsg.TargetAccount) -		case gtsmodel.ActivityStreamsAnnounce: +		case ap.ActivityAnnounce:  			// UNDO ANNOUNCE/BOOST  			boost, ok := clientMsg.GTSModel.(*gtsmodel.Status)  			if !ok { @@ -177,10 +179,10 @@ func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel  			return p.federateUnannounce(ctx, boost, clientMsg.OriginAccount, clientMsg.TargetAccount)  		} -	case gtsmodel.ActivityStreamsDelete: +	case ap.ActivityDelete:  		// DELETE  		switch clientMsg.APObjectType { -		case gtsmodel.ActivityStreamsNote: +		case ap.ObjectNote:  			// DELETE STATUS/NOTE  			statusToDelete, ok := clientMsg.GTSModel.(*gtsmodel.Status)  			if !ok { @@ -216,7 +218,7 @@ func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel  			}  			return p.federateStatusDelete(ctx, statusToDelete) -		case gtsmodel.ActivityStreamsProfile, gtsmodel.ActivityStreamsPerson: +		case ap.ObjectProfile, ap.ActorPerson:  			// DELETE ACCOUNT/PROFILE  			// the origin of the delete could be either a domain block, or an action by another (or this) account diff --git a/internal/processing/fromfederator.go b/internal/processing/fromfederator.go index 2bb74db34..49587b357 100644 --- a/internal/processing/fromfederator.go +++ b/internal/processing/fromfederator.go @@ -25,12 +25,14 @@ import (  	"net/url"  	"github.com/sirupsen/logrus" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/id" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  ) -func (p *processor) processFromFederator(ctx context.Context, federatorMsg gtsmodel.FromFederator) error { +func (p *processor) processFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error {  	l := p.log.WithFields(logrus.Fields{  		"func":         "processFromFederator",  		"federatorMsg": fmt.Sprintf("%+v", federatorMsg), @@ -39,10 +41,10 @@ func (p *processor) processFromFederator(ctx context.Context, federatorMsg gtsmo  	l.Trace("entering function PROCESS FROM FEDERATOR")  	switch federatorMsg.APActivityType { -	case gtsmodel.ActivityStreamsCreate: +	case ap.ActivityCreate:  		// CREATE  		switch federatorMsg.APObjectType { -		case gtsmodel.ActivityStreamsNote: +		case ap.ObjectNote:  			// CREATE A STATUS  			incomingStatus, ok := federatorMsg.GTSModel.(*gtsmodel.Status)  			if !ok { @@ -61,10 +63,10 @@ func (p *processor) processFromFederator(ctx context.Context, federatorMsg gtsmo  			if err := p.notifyStatus(ctx, status); err != nil {  				return err  			} -		case gtsmodel.ActivityStreamsProfile: +		case ap.ObjectProfile:  			// CREATE AN ACCOUNT  			// nothing to do here -		case gtsmodel.ActivityStreamsLike: +		case ap.ActivityLike:  			// CREATE A FAVE  			incomingFave, ok := federatorMsg.GTSModel.(*gtsmodel.StatusFave)  			if !ok { @@ -74,7 +76,7 @@ func (p *processor) processFromFederator(ctx context.Context, federatorMsg gtsmo  			if err := p.notifyFave(ctx, incomingFave, federatorMsg.ReceivingAccount); err != nil {  				return err  			} -		case gtsmodel.ActivityStreamsFollow: +		case ap.ActivityFollow:  			// CREATE A FOLLOW REQUEST  			incomingFollowRequest, ok := federatorMsg.GTSModel.(*gtsmodel.FollowRequest)  			if !ok { @@ -84,7 +86,7 @@ func (p *processor) processFromFederator(ctx context.Context, federatorMsg gtsmo  			if err := p.notifyFollowRequest(ctx, incomingFollowRequest, federatorMsg.ReceivingAccount); err != nil {  				return err  			} -		case gtsmodel.ActivityStreamsAnnounce: +		case ap.ActivityAnnounce:  			// CREATE AN ANNOUNCE  			incomingAnnounce, ok := federatorMsg.GTSModel.(*gtsmodel.Status)  			if !ok { @@ -114,7 +116,7 @@ func (p *processor) processFromFederator(ctx context.Context, federatorMsg gtsmo  			if err := p.notifyAnnounce(ctx, incomingAnnounce); err != nil {  				return err  			} -		case gtsmodel.ActivityStreamsBlock: +		case ap.ActivityBlock:  			// CREATE A BLOCK  			block, ok := federatorMsg.GTSModel.(*gtsmodel.Block)  			if !ok { @@ -131,10 +133,10 @@ func (p *processor) processFromFederator(ctx context.Context, federatorMsg gtsmo  			// TODO: same with notifications  			// TODO: same with bookmarks  		} -	case gtsmodel.ActivityStreamsUpdate: +	case ap.ActivityUpdate:  		// UPDATE  		switch federatorMsg.APObjectType { -		case gtsmodel.ActivityStreamsProfile: +		case ap.ObjectProfile:  			// UPDATE AN ACCOUNT  			incomingAccount, ok := federatorMsg.GTSModel.(*gtsmodel.Account)  			if !ok { @@ -150,10 +152,10 @@ func (p *processor) processFromFederator(ctx context.Context, federatorMsg gtsmo  				return fmt.Errorf("error dereferencing account from federator: %s", err)  			}  		} -	case gtsmodel.ActivityStreamsDelete: +	case ap.ActivityDelete:  		// DELETE  		switch federatorMsg.APObjectType { -		case gtsmodel.ActivityStreamsNote: +		case ap.ObjectNote:  			// DELETE A STATUS  			// TODO: handle side effects of status deletion here:  			// 1. delete all media associated with status @@ -185,14 +187,14 @@ func (p *processor) processFromFederator(ctx context.Context, federatorMsg gtsmo  			// remove this status from any and all timelines  			return p.deleteStatusFromTimelines(ctx, statusToDelete) -		case gtsmodel.ActivityStreamsProfile: +		case ap.ObjectProfile:  			// DELETE A PROFILE/ACCOUNT  			// TODO: handle side effects of account deletion here: delete all objects, statuses, media etc associated with account  		} -	case gtsmodel.ActivityStreamsAccept: +	case ap.ActivityAccept:  		// ACCEPT  		switch federatorMsg.APObjectType { -		case gtsmodel.ActivityStreamsFollow: +		case ap.ActivityFollow:  			// ACCEPT A FOLLOW  			follow, ok := federatorMsg.GTSModel.(*gtsmodel.Follow)  			if !ok { diff --git a/internal/processing/processor.go b/internal/processing/processor.go index 8df464ce0..1ade38564 100644 --- a/internal/processing/processor.go +++ b/internal/processing/processor.go @@ -32,6 +32,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/media" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/oauth"  	"github.com/superseriousbusiness/gotosocial/internal/processing/account"  	"github.com/superseriousbusiness/gotosocial/internal/processing/admin" @@ -219,8 +220,8 @@ type Processor interface {  // processor just implements the Processor interface  type processor struct { -	fromClientAPI   chan gtsmodel.FromClientAPI -	fromFederator   chan gtsmodel.FromFederator +	fromClientAPI   chan messages.FromClientAPI +	fromFederator   chan messages.FromFederator  	federator       federation.Federator  	stop            chan interface{}  	log             *logrus.Logger @@ -247,8 +248,8 @@ type processor struct {  // NewProcessor returns a new Processor that uses the given federator and logger  func NewProcessor(config *config.Config, tc typeutils.TypeConverter, federator federation.Federator, oauthServer oauth.Server, mediaHandler media.Handler, storage blob.Storage, timelineManager timeline.Manager, db db.DB, log *logrus.Logger) Processor { -	fromClientAPI := make(chan gtsmodel.FromClientAPI, 1000) -	fromFederator := make(chan gtsmodel.FromFederator, 1000) +	fromClientAPI := make(chan messages.FromClientAPI, 1000) +	fromFederator := make(chan messages.FromFederator, 1000)  	statusProcessor := status.New(db, tc, config, fromClientAPI, log)  	streamingProcessor := streaming.New(db, tc, oauthServer, config, log) diff --git a/internal/processing/status/boost.go b/internal/processing/status/boost.go index 66118ce2f..d6c4ada41 100644 --- a/internal/processing/status/boost.go +++ b/internal/processing/status/boost.go @@ -23,9 +23,11 @@ import (  	"errors"  	"fmt" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  )  func (p *processor) Boost(ctx context.Context, requestingAccount *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { @@ -63,9 +65,9 @@ func (p *processor) Boost(ctx context.Context, requestingAccount *gtsmodel.Accou  	}  	// send it back to the processor for async processing -	p.fromClientAPI <- gtsmodel.FromClientAPI{ -		APObjectType:   gtsmodel.ActivityStreamsAnnounce, -		APActivityType: gtsmodel.ActivityStreamsCreate, +	p.fromClientAPI <- messages.FromClientAPI{ +		APObjectType:   ap.ActivityAnnounce, +		APActivityType: ap.ActivityCreate,  		GTSModel:       boostWrapperStatus,  		OriginAccount:  requestingAccount,  		TargetAccount:  targetStatus.Account, diff --git a/internal/processing/status/create.go b/internal/processing/status/create.go index 2e0b30ad8..a87dbc7fe 100644 --- a/internal/processing/status/create.go +++ b/internal/processing/status/create.go @@ -23,10 +23,12 @@ import (  	"fmt"  	"time" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/id" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/text"  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) @@ -50,7 +52,7 @@ func (p *processor) Create(ctx context.Context, account *gtsmodel.Account, appli  		AccountID:                account.ID,  		AccountURI:               account.URI,  		ContentWarning:           text.RemoveHTML(form.SpoilerText), -		ActivityStreamsType:      gtsmodel.ActivityStreamsNote, +		ActivityStreamsType:      ap.ObjectNote,  		Sensitive:                form.Sensitive,  		Language:                 form.Language,  		CreatedWithApplicationID: application.ID, @@ -95,9 +97,9 @@ func (p *processor) Create(ctx context.Context, account *gtsmodel.Account, appli  	}  	// send it back to the processor for async processing -	p.fromClientAPI <- gtsmodel.FromClientAPI{ -		APObjectType:   gtsmodel.ActivityStreamsNote, -		APActivityType: gtsmodel.ActivityStreamsCreate, +	p.fromClientAPI <- messages.FromClientAPI{ +		APObjectType:   ap.ObjectNote, +		APActivityType: ap.ActivityCreate,  		GTSModel:       newStatus,  		OriginAccount:  account,  	} diff --git a/internal/processing/status/delete.go b/internal/processing/status/delete.go index daa7a934f..dfb2c3626 100644 --- a/internal/processing/status/delete.go +++ b/internal/processing/status/delete.go @@ -23,9 +23,11 @@ import (  	"errors"  	"fmt" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  )  func (p *processor) Delete(ctx context.Context, requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { @@ -51,9 +53,9 @@ func (p *processor) Delete(ctx context.Context, requestingAccount *gtsmodel.Acco  	}  	// send it back to the processor for async processing -	p.fromClientAPI <- gtsmodel.FromClientAPI{ -		APObjectType:   gtsmodel.ActivityStreamsNote, -		APActivityType: gtsmodel.ActivityStreamsDelete, +	p.fromClientAPI <- messages.FromClientAPI{ +		APObjectType:   ap.ObjectNote, +		APActivityType: ap.ActivityDelete,  		GTSModel:       targetStatus,  		OriginAccount:  requestingAccount,  		TargetAccount:  requestingAccount, diff --git a/internal/processing/status/fave.go b/internal/processing/status/fave.go index 410c94056..195bfa56a 100644 --- a/internal/processing/status/fave.go +++ b/internal/processing/status/fave.go @@ -23,11 +23,13 @@ import (  	"errors"  	"fmt" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/id" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/util"  ) @@ -82,9 +84,9 @@ func (p *processor) Fave(ctx context.Context, requestingAccount *gtsmodel.Accoun  		}  		// send it back to the processor for async processing -		p.fromClientAPI <- gtsmodel.FromClientAPI{ -			APObjectType:   gtsmodel.ActivityStreamsLike, -			APActivityType: gtsmodel.ActivityStreamsCreate, +		p.fromClientAPI <- messages.FromClientAPI{ +			APObjectType:   ap.ActivityLike, +			APActivityType: ap.ActivityCreate,  			GTSModel:       gtsFave,  			OriginAccount:  requestingAccount,  			TargetAccount:  targetStatus.Account, diff --git a/internal/processing/status/status.go b/internal/processing/status/status.go index 37790d062..10faa5696 100644 --- a/internal/processing/status/status.go +++ b/internal/processing/status/status.go @@ -27,6 +27,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/text"  	"github.com/superseriousbusiness/gotosocial/internal/typeutils"  	"github.com/superseriousbusiness/gotosocial/internal/visibility" @@ -75,12 +76,12 @@ type processor struct {  	db            db.DB  	filter        visibility.Filter  	formatter     text.Formatter -	fromClientAPI chan gtsmodel.FromClientAPI +	fromClientAPI chan messages.FromClientAPI  	log           *logrus.Logger  }  // New returns a new status processor. -func New(db db.DB, tc typeutils.TypeConverter, config *config.Config, fromClientAPI chan gtsmodel.FromClientAPI, log *logrus.Logger) Processor { +func New(db db.DB, tc typeutils.TypeConverter, config *config.Config, fromClientAPI chan messages.FromClientAPI, log *logrus.Logger) Processor {  	return &processor{  		tc:            tc,  		config:        config, diff --git a/internal/processing/status/status_test.go b/internal/processing/status/status_test.go index ba95a96a8..90f4187a9 100644 --- a/internal/processing/status/status_test.go +++ b/internal/processing/status/status_test.go @@ -24,6 +24,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/config"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/oauth"  	"github.com/superseriousbusiness/gotosocial/internal/processing/status"  	"github.com/superseriousbusiness/gotosocial/internal/typeutils" @@ -36,7 +37,7 @@ type StatusStandardTestSuite struct {  	db                db.DB  	log               *logrus.Logger  	typeConverter     typeutils.TypeConverter -	fromClientAPIChan chan gtsmodel.FromClientAPI +	fromClientAPIChan chan messages.FromClientAPI  	// standard suite models  	testTokens       map[string]*oauth.Token diff --git a/internal/processing/status/unboost.go b/internal/processing/status/unboost.go index c3c667a71..13c24d638 100644 --- a/internal/processing/status/unboost.go +++ b/internal/processing/status/unboost.go @@ -23,10 +23,12 @@ import (  	"errors"  	"fmt" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  )  func (p *processor) Unboost(ctx context.Context, requestingAccount *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { @@ -89,9 +91,9 @@ func (p *processor) Unboost(ctx context.Context, requestingAccount *gtsmodel.Acc  		gtsBoost.BoostOf.Account = targetStatus.Account  		// send it back to the processor for async processing -		p.fromClientAPI <- gtsmodel.FromClientAPI{ -			APObjectType:   gtsmodel.ActivityStreamsAnnounce, -			APActivityType: gtsmodel.ActivityStreamsUndo, +		p.fromClientAPI <- messages.FromClientAPI{ +			APObjectType:   ap.ActivityAnnounce, +			APActivityType: ap.ActivityUndo,  			GTSModel:       gtsBoost,  			OriginAccount:  requestingAccount,  			TargetAccount:  targetStatus.Account, diff --git a/internal/processing/status/unfave.go b/internal/processing/status/unfave.go index 3d079e2ff..27ce9b156 100644 --- a/internal/processing/status/unfave.go +++ b/internal/processing/status/unfave.go @@ -23,10 +23,12 @@ import (  	"errors"  	"fmt" +	"github.com/superseriousbusiness/gotosocial/internal/ap"  	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/gtserror"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  )  func (p *processor) Unfave(ctx context.Context, requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { @@ -71,9 +73,9 @@ func (p *processor) Unfave(ctx context.Context, requestingAccount *gtsmodel.Acco  		}  		// send it back to the processor for async processing -		p.fromClientAPI <- gtsmodel.FromClientAPI{ -			APObjectType:   gtsmodel.ActivityStreamsLike, -			APActivityType: gtsmodel.ActivityStreamsUndo, +		p.fromClientAPI <- messages.FromClientAPI{ +			APObjectType:   ap.ActivityLike, +			APActivityType: ap.ActivityUndo,  			GTSModel:       gtsFave,  			OriginAccount:  requestingAccount,  			TargetAccount:  targetStatus.Account, diff --git a/internal/processing/status/util_test.go b/internal/processing/status/util_test.go index 1ec2076b1..f80cf9342 100644 --- a/internal/processing/status/util_test.go +++ b/internal/processing/status/util_test.go @@ -27,6 +27,7 @@ import (  	"github.com/stretchr/testify/suite"  	"github.com/superseriousbusiness/gotosocial/internal/api/model"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" +	"github.com/superseriousbusiness/gotosocial/internal/messages"  	"github.com/superseriousbusiness/gotosocial/internal/processing/status"  	"github.com/superseriousbusiness/gotosocial/testrig"  ) @@ -68,7 +69,7 @@ func (suite *UtilTestSuite) SetupTest() {  	suite.db = testrig.NewTestDB()  	suite.log = testrig.NewTestLog()  	suite.typeConverter = testrig.NewTestTypeConverter(suite.db) -	suite.fromClientAPIChan = make(chan gtsmodel.FromClientAPI, 100) +	suite.fromClientAPIChan = make(chan messages.FromClientAPI, 100)  	suite.status = status.New(suite.db, suite.typeConverter, suite.config, suite.fromClientAPIChan, suite.log)  	testrig.StandardDBSetup(suite.db, nil) diff --git a/internal/typeutils/astointernal.go b/internal/typeutils/astointernal.go index 04d9cd824..5e5ee8e45 100644 --- a/internal/typeutils/astointernal.go +++ b/internal/typeutils/astointernal.go @@ -94,15 +94,15 @@ func (c *converter) ASRepresentationToAccount(ctx context.Context, accountable a  	// check for bot and actor type  	switch accountable.GetTypeName() { -	case gtsmodel.ActivityStreamsPerson, gtsmodel.ActivityStreamsGroup, gtsmodel.ActivityStreamsOrganization: +	case ap.ActorPerson, ap.ActorGroup, ap.ActorOrganization:  		// people, groups, and organizations aren't bots  		acct.Bot = false  		// apps and services are -	case gtsmodel.ActivityStreamsApplication, gtsmodel.ActivityStreamsService: +	case ap.ActorApplication, ap.ActorService:  		acct.Bot = true  	default:  		// we don't know what this is! -		return nil, fmt.Errorf("type name %s not recognised or not convertible to gtsmodel.ActivityStreamsActor", accountable.GetTypeName()) +		return nil, fmt.Errorf("type name %s not recognised or not convertible to ap.ActivityStreamsActor", accountable.GetTypeName())  	}  	acct.ActorType = accountable.GetTypeName() | 
