more fiddling

This commit is contained in:
tsmethurst 2021-08-17 19:03:41 +02:00
commit a3322b2bf3
65 changed files with 712 additions and 508 deletions

View file

@ -581,7 +581,7 @@ func ExtractMention(i Mentionable) (*gtsmodel.Mention, error) {
if hrefProp == nil || !hrefProp.IsIRI() {
return nil, errors.New("no href prop")
}
mention.MentionedAccountURI = hrefProp.GetIRI().String()
mention.TargetAccountURI = hrefProp.GetIRI().String()
return mention, nil
}

View file

@ -1,3 +1,21 @@
/*
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 db
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"

View file

@ -1,3 +1,21 @@
/*
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 db
import (

View file

@ -1,3 +1,21 @@
/*
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 db
import "context"
@ -11,6 +29,10 @@ type Basic interface {
// For implementations that don't use tables, this can just return nil.
DropTable(i interface{}) DBError
// RegisterTable registers a table for use in many2many relations.
// For implementations that don't use tables, or many2many relations, this can just return nil.
RegisterTable(i interface{}) DBError
// Stop should stop and close the database connection cleanly, returning an error if this is not possible.
// If the database implementation doesn't need to be stopped, this can just return nil.
Stop(ctx context.Context) DBError

View file

@ -35,6 +35,7 @@ type DB interface {
Admin
Basic
Instance
Mention
Notification
Relationship
Status

View file

@ -1,3 +1,21 @@
/*
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 db
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"

29
internal/db/mention.go Normal file
View file

@ -0,0 +1,29 @@
/*
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 db
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
type Mention interface {
// GetMention gets a single mention by ID
GetMention(id string) (*gtsmodel.Mention, DBError)
// GetMentions gets multiple mentions.
GetMentions(ids []string) ([]*gtsmodel.Mention, DBError)
}

View file

@ -1,3 +1,21 @@
/*
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 db
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"

View file

@ -185,6 +185,11 @@ func (b *basicDB) DropTable(i interface{}) db.DBError {
})
}
func (b *basicDB) RegisterTable(i interface{}) db.DBError {
orm.RegisterTable(i)
return nil
}
func (b *basicDB) IsHealthy(ctx context.Context) db.DBError {
return b.conn.Ping(ctx)
}

77
internal/db/pg/mention.go Normal file
View file

@ -0,0 +1,77 @@
/*
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 pg
import (
"context"
"github.com/go-pg/pg/v10"
"github.com/go-pg/pg/v10/orm"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
type mentionDB struct {
config *config.Config
conn *pg.DB
log *logrus.Logger
cancel context.CancelFunc
}
func (m *mentionDB) newMentionQ(i interface{}) *orm.Query {
return m.conn.Model(i).
Relation("Status").
Relation("OriginAccount").
Relation("TargetAccount")
}
func (m *mentionDB) processResponse(mention *gtsmodel.Mention, err error) (*gtsmodel.Mention, db.DBError) {
switch err {
case pg.ErrNoRows:
return nil, db.ErrNoEntries
case nil:
return mention, nil
default:
return nil, err
}
}
func (m *mentionDB) GetMention(id string) (*gtsmodel.Mention, db.DBError) {
mention := &gtsmodel.Mention{}
q := m.newMentionQ(mention).
Where("mention.id = ?", id)
return m.processResponse(mention, q.Select())
}
func (m *mentionDB) GetMentions(ids []string) ([]*gtsmodel.Mention, db.DBError) {
mentions := []*gtsmodel.Mention{}
q := m.newMentionQ(mentions).
Where("mention.id in (?)", pg.In(ids))
if err := q.Select(); err != nil {
return nil, err
}
return mentions, nil
}

View file

@ -44,6 +44,7 @@ type postgresService struct {
db.Admin
db.Basic
db.Instance
db.Mention
db.Notification
db.Relationship
db.Status
@ -116,6 +117,12 @@ func NewPostgresService(ctx context.Context, c *config.Config, log *logrus.Logge
log: log,
cancel: cancel,
},
Mention: &mentionDB{
config: c,
conn: conn,
log: log,
cancel: cancel,
},
Relationship: &relationshipDB{
config: c,
conn: conn,
@ -313,14 +320,14 @@ func (ps *postgresService) MentionStringsToMentions(targetAccounts []string, ori
// id, createdAt and updatedAt will be populated by the db, so we have everything we need!
menchies = append(menchies, &gtsmodel.Mention{
StatusID: statusID,
OriginAccountID: ogAccount.ID,
OriginAccountURI: ogAccount.URI,
TargetAccountID: mentionedAccount.ID,
NameString: a,
MentionedAccountURI: mentionedAccount.URI,
MentionedAccountURL: mentionedAccount.URL,
GTSAccount: mentionedAccount,
StatusID: statusID,
OriginAccountID: ogAccount.ID,
OriginAccountURI: ogAccount.URI,
TargetAccountID: mentionedAccount.ID,
NameString: a,
TargetAccountURI: mentionedAccount.URI,
TargetAccountURL: mentionedAccount.URL,
OriginAccount: mentionedAccount,
})
}
return menchies, nil

View file

@ -23,6 +23,7 @@ import (
"fmt"
"github.com/go-pg/pg/v10"
"github.com/go-pg/pg/v10/orm"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@ -36,21 +37,41 @@ type relationshipDB struct {
cancel context.CancelFunc
}
func (r *relationshipDB) Blocked(account1 string, account2 string) (bool, db.DBError) {
// TODO: check domain blocks as well
var blocked bool
if err := r.conn.Model(&gtsmodel.Block{}).
Where("account_id = ?", account1).Where("target_account_id = ?", account2).
WhereOr("target_account_id = ?", account1).Where("account_id = ?", account2).
Select(); err != nil {
if err == pg.ErrNoRows {
blocked = false
return blocked, nil
}
return blocked, err
func (r *relationshipDB) newBlockQ(block *gtsmodel.Block) *orm.Query {
return r.conn.Model(block).
Relation("Account").
Relation("TargetAccount")
}
func (r *relationshipDB) processResponse(block *gtsmodel.Block, err error) (*gtsmodel.Block, db.DBError) {
switch err {
case pg.ErrNoRows:
return nil, db.ErrNoEntries
case nil:
return block, nil
default:
return nil, err
}
blocked = true
return blocked, nil
}
func (r *relationshipDB) Blocked(account1 string, account2 string, eitherDirection bool) (bool, db.DBError) {
q := r.conn.Model(&gtsmodel.Block{}).Where("account_id = ?", account1).Where("target_account_id = ?", account2)
if eitherDirection {
q = q.WhereOr("target_account_id = ?", account1).Where("account_id = ?", account2)
}
return q.Exists()
}
func (r *relationshipDB) GetBlock(account1 string, account2 string) (*gtsmodel.Block, db.DBError) {
block := &gtsmodel.Block{}
q := r.newBlockQ(block).
Where("block.account_id = ?", account1).
Where("block.target_account_id = ?", account2)
return r.processResponse(block, q.Select())
}
func (r *relationshipDB) GetRelationship(requestingAccount string, targetAccount string) (*gtsmodel.Relationship, db.DBError) {

View file

@ -40,6 +40,10 @@ type statusDB struct {
func (s *statusDB) newStatusQ(status *gtsmodel.Status) *orm.Query {
return s.conn.Model(status).
Relation("Attachments").
Relation("Tags").
Relation("Mentions").
Relation("Emojis").
Relation("Account").
Relation("InReplyTo").
Relation("InReplyToAccount").
@ -48,7 +52,7 @@ func (s *statusDB) newStatusQ(status *gtsmodel.Status) *orm.Query {
Relation("CreatedWithApplication")
}
func (s *statusDB) processResponse(status *gtsmodel.Status, err error) (*gtsmodel.Status, db.DBError) {
func (s *statusDB) processStatusResponse(status *gtsmodel.Status, err error) (*gtsmodel.Status, db.DBError) {
switch err {
case pg.ErrNoRows:
return nil, db.ErrNoEntries
@ -65,7 +69,7 @@ func (s *statusDB) GetStatusByID(id string) (*gtsmodel.Status, db.DBError) {
q := s.newStatusQ(status).
Where("status.id = ?", id)
return s.processResponse(status, q.Select())
return s.processStatusResponse(status, q.Select())
}
func (s *statusDB) GetStatusByURI(uri string) (*gtsmodel.Status, db.DBError) {
@ -74,7 +78,7 @@ func (s *statusDB) GetStatusByURI(uri string) (*gtsmodel.Status, db.DBError) {
q := s.newStatusQ(status).
Where("LOWER(status.uri) = LOWER(?)", uri)
return s.processResponse(status, q.Select())
return s.processStatusResponse(status, q.Select())
}
func (s *statusDB) StatusParents(status *gtsmodel.Status, onlyDirect bool) ([]*gtsmodel.Status, db.DBError) {

View file

@ -80,7 +80,18 @@ func (suite *PGStandardTestSuite) TestGetStatusByURI() {
suite.Nil(status.InReplyTo)
suite.Nil(status.InReplyToAccount)
}
func (suite *PGStandardTestSuite) TestGetStatusWithExtras() {
status, err := suite.db.GetStatusByID(suite.testStatuses["admin_account_status_1"].ID)
if err != nil {
suite.FailNow(err.Error())
}
suite.NotNil(status)
suite.NotNil(status.Account)
suite.NotNil(status.CreatedWithApplication)
suite.NotEmpty(status.Tags)
suite.NotEmpty(status.Attachments)
suite.NotEmpty(status.Emojis)
}
func TestStatusTestSuite(t *testing.T) {
suite.Run(t, new(PGStandardTestSuite))
}

View file

@ -1,11 +1,35 @@
/*
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 db
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
type Relationship interface {
// Blocked checks whether a block exists in eiher direction between two accounts.
// That is, it returns true if account1 blocks account2, OR if account2 blocks account1.
Blocked(account1 string, account2 string) (bool, DBError)
// Blocked checks whether account 1 has a block in place against block2.
// If eitherDirection is true, then the function returns true if account1 blocks account2, OR if account2 blocks account1.
Blocked(account1 string, account2 string, eitherDirection bool) (bool, DBError)
// GetBlock returns the block from account1 targeting account2, if it exists, or an error if it doesn't.
//
// Because this is slower than Blocked, only use it if you need the actual Block struct for some reason,
// not if you're just checking for the existence of a block.
GetBlock(account1 string, account2 string) (*gtsmodel.Block, DBError)
// GetRelationship retrieves the relationship of the targetAccount to the requestingAccount.
GetRelationship(requestingAccount string, targetAccount string) (*gtsmodel.Relationship, DBError)

View file

@ -1,3 +1,21 @@
/*
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 db
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"

View file

@ -1,3 +1,21 @@
/*
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 db
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"

View file

@ -276,7 +276,7 @@ func (d *deref) populateStatusFields(status *gtsmodel.Status, requestingUsername
// * the remote URL (a.RemoteURL)
// This should be enough to pass along to the media processor.
attachmentIDs := []string{}
for _, a := range status.GTSMediaAttachments {
for _, a := range status.Attachments {
l.Tracef("dereferencing attachment: %+v", a)
// it might have been processed elsewhere so check first if it's already in the database or not
@ -307,7 +307,7 @@ func (d *deref) populateStatusFields(status *gtsmodel.Status, requestingUsername
}
attachmentIDs = append(attachmentIDs, deferencedAttachment.ID)
}
status.Attachments = attachmentIDs
status.AttachmentIDs = attachmentIDs
// 2. Hashtags
@ -318,7 +318,7 @@ func (d *deref) populateStatusFields(status *gtsmodel.Status, requestingUsername
//
// We should dereference any accounts mentioned here which we don't have in our db yet, by their URI.
mentions := []string{}
for _, m := range status.GTSMentions {
for _, m := range status.Mentions {
if m.ID != "" {
continue
@ -331,9 +331,9 @@ func (d *deref) populateStatusFields(status *gtsmodel.Status, requestingUsername
}
m.ID = mID
uri, err := url.Parse(m.MentionedAccountURI)
uri, err := url.Parse(m.TargetAccountURI)
if err != nil {
l.Debugf("error parsing mentioned account uri %s: %s", m.MentionedAccountURI, err)
l.Debugf("error parsing mentioned account uri %s: %s", m.TargetAccountURI, err)
continue
}
@ -353,7 +353,7 @@ func (d *deref) populateStatusFields(status *gtsmodel.Status, requestingUsername
}
mentions = append(mentions, m.ID)
}
status.Mentions = mentions
status.MentionIDs = mentions
// status has replyToURI but we don't have an ID yet for the status it replies to
if status.InReplyToURI != "" && status.InReplyToID == "" {

View file

@ -32,6 +32,7 @@ type DomainBlock struct {
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Account ID of the creator of this block
CreatedByAccountID string `pg:"type:CHAR(26),notnull"`
CreatedByAccount *Account `pg:"rel:belongs-to"`
// Private comment on this block, viewable to admins
PrivateComment string
// Public comment on this block, viewable (optionally) by everyone

View file

@ -32,4 +32,5 @@ type EmailDomainBlock struct {
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Account ID of the creator of this block
CreatedByAccountID string `pg:"type:CHAR(26),notnull"`
CreatedByAccount *Account `pg:"rel:belongs-to"`
}

View file

@ -73,5 +73,6 @@ type Emoji struct {
// Is this emoji visible in the admin emoji picker?
VisibleInPicker bool `pg:",notnull,default:true"`
// In which emoji category is this emoji visible?
CategoryID string `pg:"type:CHAR(26)"`
CategoryID string `pg:"type:CHAR(26)"`
Status *Status `pg:"rel:belongs-to"`
}

View file

@ -30,8 +30,10 @@ type Follow struct {
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Who does this follow belong to?
AccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
Account *Account `pg:"rel:belongs-to"`
// Who does AccountID follow?
TargetAccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
TargetAccount *Account `pg:"rel:has-one"`
// Does this follow also want to see reblogs and not just posts?
ShowReblogs bool `pg:"default:true"`
// What is the activitypub URI of this follow?

View file

@ -29,9 +29,11 @@ type FollowRequest struct {
// When was this follow request last updated?
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Who does this follow request originate from?
AccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
AccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
Account Account `pg:"rel:has-one"`
// Who is the target of this follow request?
TargetAccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
TargetAccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
TargetAccount Account `pg:"rel:has-one"`
// Does this follow also want to see reblogs and not just posts?
ShowReblogs bool `pg:"default:true"`
// What is the activitypub URI of this follow request?

View file

@ -43,6 +43,7 @@ type MediaAttachment struct {
FileMeta FileMeta
// To which account does this attachment belong
AccountID string `pg:"type:CHAR(26),notnull"`
Account *Account `pg:"rel:belongs-to"`
// Description of the attachment (for screenreaders)
Description string
// To which scheduled status does this attachment belong

View file

@ -26,16 +26,19 @@ type Mention struct {
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
// ID of the status this mention originates from
StatusID string `pg:"type:CHAR(26),notnull"`
Status *Status `pg:"rel:belongs-to"`
// When was this mention created?
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// When was this mention last updated?
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// What's the internal account ID of the originator of the mention?
OriginAccountID string `pg:"type:CHAR(26),notnull"`
OriginAccount *Account `pg:"rel:has-one"`
// What's the AP URI of the originator of the mention?
OriginAccountURI string `pg:",notnull"`
// What's the internal account ID of the mention target?
TargetAccountID string `pg:"type:CHAR(26),notnull"`
TargetAccount *Account `pg:"rel:has-one"`
// Prevent this mention from generating a notification?
Silent bool
@ -52,14 +55,14 @@ type Mention struct {
//
// This will not be put in the database, it's just for convenience.
NameString string `pg:"-"`
// MentionedAccountURI is the AP ID (uri) of the user mentioned.
// TargetAccountURI is the AP ID (uri) of the user mentioned.
//
// This will not be put in the database, it's just for convenience.
MentionedAccountURI string `pg:"-"`
// MentionedAccountURL is the web url of the user mentioned.
TargetAccountURI string `pg:"-"`
// TargetAccountURL is the web url of the user mentioned.
//
// This will not be put in the database, it's just for convenience.
MentionedAccountURL string `pg:"-"`
TargetAccountURL string `pg:"-"`
// A pointer to the gtsmodel account of the mentioned account.
GTSAccount *Account `pg:"-"`
}

View file

@ -29,24 +29,16 @@ type Notification struct {
// Creation time of this notification
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// Which account does this notification target (ie., who will receive the notification?)
TargetAccountID string `pg:"type:CHAR(26),notnull"`
TargetAccountID string `pg:"type:CHAR(26),notnull"`
TargetAccount *Account `pg:"rel:has-one"`
// Which account performed the action that created this notification?
OriginAccountID string `pg:"type:CHAR(26),notnull"`
OriginAccountID string `pg:"type:CHAR(26),notnull"`
OriginAccount *Account `pg:"rel:has-one"`
// If the notification pertains to a status, what is the database ID of that status?
StatusID string `pg:"type:CHAR(26)"`
StatusID string `pg:"type:CHAR(26)"`
Status *Status `pg:"rel:has-one"`
// Has this notification been read already?
Read bool
/*
NON-DATABASE fields
*/
// gts model of the target account, won't be put in the database, it's just for convenience when passing the notification around.
GTSTargetAccount *Account `pg:"-"`
// gts model of the origin account, won't be put in the database, it's just for convenience when passing the notification around.
GTSOriginAccount *Account `pg:"-"`
// gts model of the relevant status, won't be put in the database, it's just for convenience when passing the notification around.
GTSStatus *Status `pg:"-"`
}
// NotificationType describes the reason/type of this notification.

View file

@ -33,13 +33,17 @@ type Status struct {
// the html-formatted content of this status
Content string
// Database IDs of any media attachments associated with this status
Attachments []string `pg:",array"`
AttachmentIDs []string `pg:"attachments,array"`
Attachments []*MediaAttachment `pg:"rel:has-many"`
// Database IDs of any tags used in this status
Tags []string `pg:",array"`
TagIDs []string `pg:"tags,array"`
Tags []*Tag `pg:"rel:has-many"`
// Database IDs of any mentions in this status
Mentions []string `pg:",array"`
MentionIDs []string `pg:"mentions,array"`
Mentions []*Mention `pg:"rel:has-many"`
// Database IDs of any emojis used in this status
Emojis []string `pg:",array"`
EmojiIDs []string `pg:"emojis,array"`
Emojis []*Emoji `pg:"rel:many2many"`
// when was this status created?
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// when was this status updated?
@ -85,25 +89,6 @@ type Status struct {
Text string
// Has this status been pinned by its owner?
Pinned bool
/*
INTERNAL MODEL NON-DATABASE FIELDS
These are for convenience while passing the status around internally,
but these fields should *never* be put in the db.
*/
// Account that created this status
// Mentions created in this status
GTSMentions []*Mention `pg:"-"`
// Hashtags used in this status
GTSTags []*Tag `pg:"-"`
// Emojis used in this status
GTSEmojis []*Emoji `pg:"-"`
// MediaAttachments used in this status
GTSMediaAttachments []*MediaAttachment `pg:"-"`
}
// Visibility represents the visibility granularity of a status.

View file

@ -28,8 +28,10 @@ type StatusBookmark struct {
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// id of the account that created ('did') the bookmarking
AccountID string `pg:"type:CHAR(26),notnull"`
Account *Account `pg:"rel:belongs-to"`
// id the account owning the bookmarked status
TargetAccountID string `pg:"type:CHAR(26),notnull"`
TargetAccount *Account `pg:"rel:has-one"`
// database id of the status that has been bookmarked
StatusID string `pg:"type:CHAR(26),notnull"`
}

View file

@ -28,7 +28,7 @@ type StatusFave struct {
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// id of the account that created ('did') the fave
AccountID string `pg:"type:CHAR(26),notnull"`
Account *Account `pg:"rel:has-one"`
Account *Account `pg:"rel:belongs-to"`
// id the account owning the faved status
TargetAccountID string `pg:"type:CHAR(26),notnull"`
TargetAccount *Account `pg:"rel:has-one"`

View file

@ -28,8 +28,11 @@ type StatusMute struct {
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
// id of the account that created ('did') the mute
AccountID string `pg:"type:CHAR(26),notnull"`
Account *Account `pg:"rel:belongs-to"`
// id the account owning the muted status (can be the same as accountID)
TargetAccountID string `pg:"type:CHAR(26),notnull"`
TargetAccount *Account `pg:"rel:has-one"`
// database id of the status that has been muted
StatusID string `pg:"type:CHAR(26),notnull"`
Status *Status `pg:"rel:has-one"`
}

View file

@ -35,7 +35,8 @@ type User struct {
// confirmed email address for this user, this should be unique -- only one email address registered per instance, multiple users per email are not supported
Email string `pg:"default:null,unique"`
// The id of the local gtsmodel.Account entry for this user, if it exists (unconfirmed users don't have an account yet)
AccountID string `pg:"type:CHAR(26),unique"`
AccountID string `pg:"type:CHAR(26),unique"`
Account *Account `pg:"rel:has-one"`
// The encrypted password of this user, generated using https://pkg.go.dev/golang.org/x/crypto/bcrypt#GenerateFromPassword. A salt is included so we're safe against 🌈 tables
EncryptedPassword string `pg:",notnull"`
@ -68,7 +69,8 @@ type User struct {
// In what timezone/locale is this user located?
Locale string
// Which application id created this user? See gtsmodel.Application
CreatedByApplicationID string `pg:"type:CHAR(26)"`
CreatedByApplicationID string `pg:"type:CHAR(26)"`
CreatedByApplication *Application `pg:"rel:has-one"`
// When did we last contact this user
LastEmailedAt time.Time `pg:"type:timestamp"`

View file

@ -31,24 +31,20 @@ import (
func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) {
// make sure the target account actually exists in our db
targetAcct := &gtsmodel.Account{}
if err := p.db.GetByID(targetAccountID, targetAcct); err != nil {
if err == db.ErrNoEntries {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("BlockCreate: account %s not found in the db: %s", targetAccountID, err))
}
targetAccount, err := p.db.GetAccountByID(targetAccountID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("BlockCreate: error getting account %s from the db: %s", targetAccountID, err))
}
// if requestingAccount already blocks target account, we don't need to do anything
block := &gtsmodel.Block{}
if err := p.db.GetWhere([]db.Where{
{Key: "account_id", Value: requestingAccount.ID},
{Key: "target_account_id", Value: targetAccountID},
}, block); err == nil {
// block already exists, just return relationship
if blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID, false); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("BlockCreate: error checking existence of block: %s", err))
} else if blocked {
return p.RelationshipGet(requestingAccount, targetAccountID)
}
// make the block
block := &gtsmodel.Block{}
newBlockID, err := id.NewULID()
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
@ -57,7 +53,7 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou
block.AccountID = requestingAccount.ID
block.Account = requestingAccount
block.TargetAccountID = targetAccountID
block.TargetAccount = targetAcct
block.TargetAccount = targetAccount
block.URI = util.GenerateURIForBlock(requestingAccount.Username, p.config.Protocol, p.config.Host, newBlockID)
// whack it in the database
@ -123,7 +119,7 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou
URI: frURI,
},
OriginAccount: requestingAccount,
TargetAccount: targetAcct,
TargetAccount: targetAccount,
}
}
@ -138,7 +134,7 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou
URI: fURI,
},
OriginAccount: requestingAccount,
TargetAccount: targetAcct,
TargetAccount: targetAccount,
}
}
@ -148,7 +144,7 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou
APActivityType: gtsmodel.ActivityStreamsCreate,
GTSModel: block,
OriginAccount: requestingAccount,
TargetAccount: targetAcct,
TargetAccount: targetAccount,
}
return p.RelationshipGet(requestingAccount, targetAccountID)

View file

@ -31,38 +31,33 @@ import (
func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) {
// if there's a block between the accounts we shouldn't create the request ofc
blocked, err := p.db.Blocked(requestingAccount.ID, form.ID)
if err != nil {
if blocked, err := p.db.Blocked(requestingAccount.ID, form.ID, true); err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
if blocked {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("accountfollowcreate: block exists between accounts"))
} else if blocked {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts"))
}
// make sure the target account actually exists in our db
targetAcct := &gtsmodel.Account{}
if err := p.db.GetByID(form.ID, targetAcct); err != nil {
targetAcct, err := p.db.GetAccountByID(form.ID)
if err != nil {
if err == db.ErrNoEntries {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("accountfollowcreate: account %s not found in the db: %s", form.ID, err))
}
return nil, gtserror.NewErrorInternalError(err)
}
// check if a follow exists already
follows, err := p.db.Follows(requestingAccount, targetAcct)
if err != nil {
if follows, err := p.db.Follows(requestingAccount, targetAcct); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error checking follow in db: %s", err))
}
if follows {
} else if follows {
// already follows so just return the relationship
return p.RelationshipGet(requestingAccount, form.ID)
}
// check if a follow exists already
followRequested, err := p.db.FollowRequested(requestingAccount, targetAcct)
if err != nil {
// check if a follow request exists already
if followRequested, err := p.db.FollowRequested(requestingAccount, targetAcct); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error checking follow request in db: %s", err))
}
if followRequested {
} else if followRequested {
// already follow requested so just return the relationship
return p.RelationshipGet(requestingAccount, form.ID)
}

View file

@ -39,7 +39,7 @@ func (p *processor) Get(requestingAccount *gtsmodel.Account, targetAccountID str
var blocked bool
var err error
if requestingAccount != nil {
blocked, err = p.db.Blocked(requestingAccount.ID, targetAccountID)
blocked, err = p.db.Blocked(requestingAccount.ID, targetAccountID, true)
if err != nil {
return nil, fmt.Errorf("error checking account block: %s", err)
}

View file

@ -28,12 +28,9 @@ import (
)
func (p *processor) FollowersGet(requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) {
blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID)
if err != nil {
if blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID, true); err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
if blocked {
} else if blocked {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts"))
}
@ -47,7 +44,7 @@ func (p *processor) FollowersGet(requestingAccount *gtsmodel.Account, targetAcco
}
for _, f := range followers {
blocked, err := p.db.Blocked(requestingAccount.ID, f.AccountID)
blocked, err := p.db.Blocked(requestingAccount.ID, f.AccountID, true)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}

View file

@ -28,12 +28,9 @@ import (
)
func (p *processor) FollowingGet(requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) {
blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID)
if err != nil {
if blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID, true); err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
if blocked {
} else if blocked {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts"))
}
@ -47,7 +44,7 @@ func (p *processor) FollowingGet(requestingAccount *gtsmodel.Account, targetAcco
}
for _, f := range following {
blocked, err := p.db.Blocked(requestingAccount.ID, f.AccountID)
blocked, err := p.db.Blocked(requestingAccount.ID, f.AccountID, true)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}

View file

@ -28,15 +28,14 @@ import (
)
func (p *processor) StatusesGet(requestingAccount *gtsmodel.Account, targetAccountID string, limit int, excludeReplies bool, maxID string, pinnedOnly bool, mediaOnly bool) ([]apimodel.Status, gtserror.WithCode) {
targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(targetAccountID, targetAccount); err != nil {
if err == db.ErrNoEntries {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no entry found for account id %s", targetAccountID))
}
if blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID, true); err != nil {
return nil, gtserror.NewErrorInternalError(err)
} else if blocked {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts"))
}
apiStatuses := []apimodel.Status{}
statuses, err := p.db.GetAccountStatuses(targetAccountID, limit, excludeReplies, maxID, pinnedOnly, mediaOnly)
if err != nil {
if err == db.ErrNoEntries {

View file

@ -29,11 +29,9 @@ import (
func (p *processor) BlockRemove(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) {
// make sure the target account actually exists in our db
targetAcct := &gtsmodel.Account{}
if err := p.db.GetByID(targetAccountID, targetAcct); err != nil {
if err == db.ErrNoEntries {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("BlockRemove: account %s not found in the db: %s", targetAccountID, err))
}
targetAccount, err := p.db.GetAccountByID(targetAccountID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("BlockCreate: error getting account %s from the db: %s", targetAccountID, err))
}
// check if a block exists, and remove it if it does (storing the URI for later)
@ -44,7 +42,7 @@ func (p *processor) BlockRemove(requestingAccount *gtsmodel.Account, targetAccou
{Key: "target_account_id", Value: targetAccountID},
}, block); err == nil {
block.Account = requestingAccount
block.TargetAccount = targetAcct
block.TargetAccount = targetAccount
if err := p.db.DeleteByID(block.ID, &gtsmodel.Block{}); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("BlockRemove: error removing block from db: %s", err))
}
@ -58,7 +56,7 @@ func (p *processor) BlockRemove(requestingAccount *gtsmodel.Account, targetAccou
APActivityType: gtsmodel.ActivityStreamsUndo,
GTSModel: block,
OriginAccount: requestingAccount,
TargetAccount: targetAcct,
TargetAccount: targetAccount,
}
}

View file

@ -29,7 +29,7 @@ import (
func (p *processor) FollowRemove(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) {
// if there's a block between the accounts we shouldn't do anything
blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID)
blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID, true)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}

View file

@ -63,7 +63,7 @@ func (p *processor) GetFediUser(ctx context.Context, requestedUsername string, r
return nil, gtserror.NewErrorNotAuthorized(err)
}
blocked, err := p.db.Blocked(requestedAccount.ID, requestingAccount.ID)
blocked, err := p.db.Blocked(requestedAccount.ID, requestingAccount.ID, true)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
@ -107,7 +107,7 @@ func (p *processor) GetFediFollowers(ctx context.Context, requestedUsername stri
return nil, gtserror.NewErrorNotAuthorized(err)
}
blocked, err := p.db.Blocked(requestedAccount.ID, requestingAccount.ID)
blocked, err := p.db.Blocked(requestedAccount.ID, requestingAccount.ID, true)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
@ -152,7 +152,7 @@ func (p *processor) GetFediFollowing(ctx context.Context, requestedUsername stri
return nil, gtserror.NewErrorNotAuthorized(err)
}
blocked, err := p.db.Blocked(requestedAccount.ID, requestingAccount.ID)
blocked, err := p.db.Blocked(requestedAccount.ID, requestingAccount.ID, true)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
@ -199,7 +199,7 @@ func (p *processor) GetFediStatus(ctx context.Context, requestedUsername string,
// authorize the request:
// 1. check if a block exists between the requester and the requestee
blocked, err := p.db.Blocked(requestedAccount.ID, requestingAccount.ID)
blocked, err := p.db.Blocked(requestedAccount.ID, requestingAccount.ID, true)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
@ -259,7 +259,7 @@ func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername
// authorize the request:
// 1. check if a block exists between the requester and the requestee
blocked, err := p.db.Blocked(requestedAccount.ID, requestingAccount.ID)
blocked, err := p.db.Blocked(requestedAccount.ID, requestingAccount.ID, true)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}

View file

@ -192,14 +192,14 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error
}
// delete all attachments for this status
for _, a := range statusToDelete.Attachments {
for _, a := range statusToDelete.AttachmentIDs {
if err := p.mediaProcessor.Delete(a); err != nil {
return err
}
}
// delete all mentions for this status
for _, m := range statusToDelete.Mentions {
for _, m := range statusToDelete.MentionIDs {
if err := p.db.DeleteByID(m, &gtsmodel.Mention{}); err != nil {
return err
}

View file

@ -30,35 +30,35 @@ import (
func (p *processor) notifyStatus(status *gtsmodel.Status) error {
// if there are no mentions in this status then just bail
if len(status.Mentions) == 0 {
if len(status.MentionIDs) == 0 {
return nil
}
if status.GTSMentions == nil {
if status.Mentions == nil {
// there are mentions but they're not fully populated on the status yet so do this
menchies := []*gtsmodel.Mention{}
for _, m := range status.Mentions {
for _, m := range status.MentionIDs {
gtsm := &gtsmodel.Mention{}
if err := p.db.GetByID(m, gtsm); err != nil {
return fmt.Errorf("notifyStatus: error getting mention with id %s from the db: %s", m, err)
}
menchies = append(menchies, gtsm)
}
status.GTSMentions = menchies
status.Mentions = menchies
}
// now we have mentions as full gtsmodel.Mention structs on the status we can continue
for _, m := range status.GTSMentions {
for _, m := range status.Mentions {
// make sure this is a local account, otherwise we don't need to create a notification for it
if m.GTSAccount == nil {
if m.OriginAccount == nil {
a := &gtsmodel.Account{}
if err := p.db.GetByID(m.TargetAccountID, a); err != nil {
// we don't have the account or there's been an error
return fmt.Errorf("notifyStatus: error getting account with id %s from the db: %s", m.TargetAccountID, err)
}
m.GTSAccount = a
m.OriginAccount = a
}
if m.GTSAccount.Domain != "" {
if m.OriginAccount.Domain != "" {
// not a local account so skip it
continue
}
@ -103,7 +103,7 @@ func (p *processor) notifyStatus(status *gtsmodel.Status) error {
return fmt.Errorf("notifyStatus: error converting notification to masto representation: %s", err)
}
if err := p.streamingProcessor.StreamNotificationToAccount(mastoNotif, m.GTSAccount); err != nil {
if err := p.streamingProcessor.StreamNotificationToAccount(mastoNotif, m.OriginAccount); err != nil {
return fmt.Errorf("notifyStatus: error streaming notification to account: %s", err)
}
}

View file

@ -164,14 +164,14 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er
}
// delete all attachments for this status
for _, a := range statusToDelete.Attachments {
for _, a := range statusToDelete.AttachmentIDs {
if err := p.mediaProcessor.Delete(a); err != nil {
return err
}
}
// delete all mentions for this status
for _, m := range statusToDelete.Mentions {
for _, m := range statusToDelete.MentionIDs {
if err := p.db.DeleteByID(m, &gtsmodel.Mention{}); err != nil {
return err
}

View file

@ -57,7 +57,7 @@ func (p *processor) GetFile(account *gtsmodel.Account, form *apimodel.GetContent
// make sure the requesting account and the media account don't block each other
if account != nil {
blocked, err := p.db.Blocked(account.ID, form.AccountID)
blocked, err := p.db.Blocked(account.ID, form.AccountID, true)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("block status could not be established between accounts %s and %s: %s", form.AccountID, account.ID, err))
}

View file

@ -90,7 +90,7 @@ func (p *processor) SearchGet(authed *oauth.Auth, searchQuery *apimodel.SearchQu
*/
for _, foundAccount := range foundAccounts {
// make sure there's no block in either direction between the account and the requester
if blocked, err := p.db.Blocked(authed.Account.ID, foundAccount.ID); err == nil && !blocked {
if blocked, err := p.db.Blocked(authed.Account.ID, foundAccount.ID, true); err == nil && !blocked {
// all good, convert it and add it to the results
if acctMasto, err := p.tc.AccountToMastoPublic(foundAccount); err == nil && acctMasto != nil {
results.Accounts = append(results.Accounts, *acctMasto)

View file

@ -9,31 +9,22 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
func (p *processor) Boost(account *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
l := p.log.WithField("func", "StatusBoost")
l.Tracef("going to search for target status %s", targetStatusID)
targetStatus := &gtsmodel.Status{}
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
func (p *processor) Boost(requestingAccount *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
targetStatus, err := p.db.GetStatusByID(targetStatusID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
}
l.Tracef("going to search for target account %s", targetStatus.AccountID)
targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(targetStatus.AccountID, targetAccount); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching target account %s: %s", targetStatus.AccountID, err))
if targetStatus.Account == nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
}
l.Trace("going to see if status is visible")
visible, err := p.filter.StatusVisible(targetStatus, account)
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
}
if !visible {
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
}
if targetStatus.VisibilityAdvanced != nil {
if !targetStatus.VisibilityAdvanced.Boostable {
return nil, gtserror.NewErrorForbidden(errors.New("status is not boostable"))
@ -41,13 +32,13 @@ func (p *processor) Boost(account *gtsmodel.Account, application *gtsmodel.Appli
}
// it's visible! it's boostable! so let's boost the FUCK out of it
boostWrapperStatus, err := p.tc.StatusToBoost(targetStatus, account)
boostWrapperStatus, err := p.tc.StatusToBoost(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
boostWrapperStatus.CreatedWithApplicationID = application.ID
boostWrapperStatus.BoostOfAccount = targetAccount
boostWrapperStatus.BoostOfAccount = targetStatus.Account
// put the boost in the database
if err := p.db.Put(boostWrapperStatus); err != nil {
@ -59,12 +50,12 @@ func (p *processor) Boost(account *gtsmodel.Account, application *gtsmodel.Appli
APObjectType: gtsmodel.ActivityStreamsAnnounce,
APActivityType: gtsmodel.ActivityStreamsCreate,
GTSModel: boostWrapperStatus,
OriginAccount: account,
TargetAccount: targetAccount,
OriginAccount: requestingAccount,
TargetAccount: targetStatus.Account,
}
// return the frontend representation of the new status to the submitter
mastoStatus, err := p.tc.StatusToMasto(boostWrapperStatus, account)
mastoStatus, err := p.tc.StatusToMasto(boostWrapperStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
}

View file

@ -9,29 +9,21 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
func (p *processor) BoostedBy(account *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) {
l := p.log.WithField("func", "StatusBoostedBy")
l.Tracef("going to search for target status %s", targetStatusID)
targetStatus := &gtsmodel.Status{}
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error fetching status %s: %s", targetStatusID, err))
}
l.Tracef("going to search for target account %s", targetStatus.AccountID)
targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(targetStatus.AccountID, targetAccount); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error fetching target account %s: %s", targetStatus.AccountID, err))
}
l.Trace("going to see if status is visible")
visible, err := p.filter.StatusVisible(targetStatus, account)
func (p *processor) BoostedBy(requestingAccount *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) {
targetStatus, err := p.db.GetStatusByID(targetStatusID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error seeing if status %s is visible: %s", targetStatus.ID, err))
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
}
if targetStatus.Account == nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
}
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
}
if !visible {
return nil, gtserror.NewErrorNotFound(errors.New("StatusBoostedBy: status is not visible"))
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
}
// get ALL accounts that faved a status -- doesn't take account of blocks and mutes and stuff
@ -43,7 +35,7 @@ func (p *processor) BoostedBy(account *gtsmodel.Account, targetStatusID string)
// filter the list so the user doesn't see accounts they blocked or which blocked them
filteredAccounts := []*gtsmodel.Account{}
for _, acc := range favingAccounts {
blocked, err := p.db.Blocked(account.ID, acc.ID)
blocked, err := p.db.Blocked(requestingAccount.ID, acc.ID, true)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error checking blocks: %s", err))
}

View file

@ -1,46 +1,45 @@
package status
import (
"errors"
"fmt"
"sort"
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"
)
func (p *processor) Context(account *gtsmodel.Account, targetStatusID string) (*apimodel.Context, gtserror.WithCode) {
func (p *processor) Context(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Context, gtserror.WithCode) {
targetStatus, err := p.db.GetStatusByID(targetStatusID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
}
if targetStatus.Account == nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
}
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
}
if !visible {
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
}
context := &apimodel.Context{
Ancestors: []apimodel.Status{},
Descendants: []apimodel.Status{},
}
targetStatus := &gtsmodel.Status{}
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
if err == db.ErrNoEntries {
return nil, gtserror.NewErrorNotFound(err)
}
return nil, gtserror.NewErrorInternalError(err)
}
visible, err := p.filter.StatusVisible(targetStatus, account)
if err != nil {
return nil, gtserror.NewErrorNotFound(err)
}
if !visible {
return nil, gtserror.NewErrorForbidden(fmt.Errorf("account with id %s does not have permission to view status %s", account.ID, targetStatusID))
}
parents, err := p.db.StatusParents(targetStatus, false)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
for _, status := range parents {
if v, err := p.filter.StatusVisible(status, account); err == nil && v {
mastoStatus, err := p.tc.StatusToMasto(status, account)
if v, err := p.filter.StatusVisible(status, requestingAccount); err == nil && v {
mastoStatus, err := p.tc.StatusToMasto(status, requestingAccount)
if err == nil {
context.Ancestors = append(context.Ancestors, *mastoStatus)
}
@ -57,8 +56,8 @@ func (p *processor) Context(account *gtsmodel.Account, targetStatusID string) (*
}
for _, status := range children {
if v, err := p.filter.StatusVisible(status, account); err == nil && v {
mastoStatus, err := p.tc.StatusToMasto(status, account)
if v, err := p.filter.StatusVisible(status, requestingAccount); err == nil && v {
mastoStatus, err := p.tc.StatusToMasto(status, requestingAccount)
if err == nil {
context.Descendants = append(context.Descendants, *mastoStatus)
}

View file

@ -81,7 +81,7 @@ func (p *processor) Create(account *gtsmodel.Account, application *gtsmodel.Appl
}
// change the status ID of the media attachments to the new status
for _, a := range newStatus.GTSMediaAttachments {
for _, a := range newStatus.Attachments {
a.StatusID = newStatus.ID
a.UpdatedAt = time.Now()
if err := p.db.UpdateByID(a.ID, a); err != nil {

View file

@ -5,36 +5,24 @@ import (
"fmt"
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"
)
func (p *processor) Delete(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
l := p.log.WithField("func", "StatusDelete")
l.Tracef("going to search for target status %s", targetStatusID)
targetStatus := &gtsmodel.Status{}
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
if err != db.ErrNoEntries {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
}
// status is already gone
return nil, nil
func (p *processor) Delete(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
targetStatus, err := p.db.GetStatusByID(targetStatusID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
}
if targetStatus.Account == nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
}
if targetStatus.AccountID != account.ID {
if targetStatus.AccountID != requestingAccount.ID {
return nil, gtserror.NewErrorForbidden(errors.New("status doesn't belong to requesting account"))
}
var boostOfStatus *gtsmodel.Status
if targetStatus.BoostOfID != "" {
boostOfStatus = &gtsmodel.Status{}
if err := p.db.GetByID(targetStatus.BoostOfID, boostOfStatus); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching boosted status %s: %s", targetStatus.BoostOfID, err))
}
}
mastoStatus, err := p.tc.StatusToMasto(targetStatus, account)
mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
}
@ -48,8 +36,8 @@ func (p *processor) Delete(account *gtsmodel.Account, targetStatusID string) (*a
APObjectType: gtsmodel.ActivityStreamsNote,
APActivityType: gtsmodel.ActivityStreamsDelete,
GTSModel: targetStatus,
OriginAccount: account,
TargetAccount: account,
OriginAccount: requestingAccount,
TargetAccount: requestingAccount,
}
return mastoStatus, nil

View file

@ -12,39 +12,22 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/util"
)
func (p *processor) Fave(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
l := p.log.WithField("func", "StatusFave")
l.Tracef("going to search for target status %s", targetStatusID)
targetStatus := &gtsmodel.Status{}
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
func (p *processor) Fave(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
targetStatus, err := p.db.GetStatusByID(targetStatusID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
}
l.Tracef("going to search for target account %s", targetStatus.AccountID)
targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(targetStatus.AccountID, targetAccount); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching target account %s: %s", targetStatus.AccountID, err))
if targetStatus.Account == nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
}
var boostOfStatus *gtsmodel.Status
if targetStatus.BoostOfID != "" {
boostOfStatus = &gtsmodel.Status{}
if err := p.db.GetByID(targetStatus.BoostOfID, boostOfStatus); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching boosted status %s: %s", targetStatus.BoostOfID, err))
}
}
l.Trace("going to see if status is visible")
visible, err := p.filter.StatusVisible(targetStatus, account) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
}
if !visible {
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
}
// is the status faveable?
if targetStatus.VisibilityAdvanced != nil {
if !targetStatus.VisibilityAdvanced.Likeable {
return nil, gtserror.NewErrorForbidden(errors.New("status is not faveable"))
@ -54,7 +37,7 @@ func (p *processor) Fave(account *gtsmodel.Account, targetStatusID string) (*api
// first check if the status is already faved, if so we don't need to do anything
newFave := true
gtsFave := &gtsmodel.StatusFave{}
if err := p.db.GetWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: account.ID}}, gtsFave); err == nil {
if err := p.db.GetWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: requestingAccount.ID}}, gtsFave); err == nil {
// we already have a fave for this status
newFave = false
}
@ -67,14 +50,14 @@ func (p *processor) Fave(account *gtsmodel.Account, targetStatusID string) (*api
// we need to create a new fave in the database
gtsFave := &gtsmodel.StatusFave{
ID: thisFaveID,
AccountID: account.ID,
TargetAccountID: targetAccount.ID,
StatusID: targetStatus.ID,
URI: util.GenerateURIForLike(account.Username, p.config.Protocol, p.config.Host, thisFaveID),
Status: targetStatus,
TargetAccount: targetAccount,
Account: account,
ID: thisFaveID,
AccountID: requestingAccount.ID,
Account: requestingAccount,
TargetAccountID: targetStatus.AccountID,
TargetAccount: targetStatus.Account,
StatusID: targetStatus.ID,
Status: targetStatus,
URI: util.GenerateURIForLike(requestingAccount.Username, p.config.Protocol, p.config.Host, thisFaveID),
}
if err := p.db.Put(gtsFave); err != nil {
@ -86,13 +69,13 @@ func (p *processor) Fave(account *gtsmodel.Account, targetStatusID string) (*api
APObjectType: gtsmodel.ActivityStreamsLike,
APActivityType: gtsmodel.ActivityStreamsCreate,
GTSModel: gtsFave,
OriginAccount: account,
TargetAccount: targetAccount,
OriginAccount: requestingAccount,
TargetAccount: targetStatus.Account,
}
}
// return the mastodon representation of the target status
mastoStatus, err := p.tc.StatusToMasto(targetStatus, account)
mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
}

View file

@ -9,27 +9,19 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
func (p *processor) FavedBy(account *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) {
l := p.log.WithField("func", "StatusFavedBy")
l.Tracef("going to search for target status %s", targetStatusID)
targetStatus := &gtsmodel.Status{}
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
func (p *processor) FavedBy(requestingAccount *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) {
targetStatus, err := p.db.GetStatusByID(targetStatusID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
}
l.Tracef("going to search for target account %s", targetStatus.AccountID)
targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(targetStatus.AccountID, targetAccount); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching target account %s: %s", targetStatus.AccountID, err))
if targetStatus.Account == nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
}
l.Trace("going to see if status is visible")
visible, err := p.filter.StatusVisible(targetStatus, account)
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
}
if !visible {
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
}
@ -43,7 +35,7 @@ func (p *processor) FavedBy(account *gtsmodel.Account, targetStatusID string) ([
// filter the list so the user doesn't see accounts they blocked or which blocked them
filteredAccounts := []*gtsmodel.Account{}
for _, acc := range favingAccounts {
blocked, err := p.db.Blocked(account.ID, acc.ID)
blocked, err := p.db.Blocked(requestingAccount.ID, acc.ID, true)
if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking blocks: %s", err))
}
@ -52,8 +44,6 @@ func (p *processor) FavedBy(account *gtsmodel.Account, targetStatusID string) ([
}
}
// TODO: filter other things here? suspended? muted? silenced?
// now we can return the masto representation of those accounts
mastoAccounts := []*apimodel.Account{}
for _, acc := range filteredAccounts {

View file

@ -9,44 +9,27 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
func (p *processor) Get(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
l := p.log.WithField("func", "StatusGet")
l.Tracef("going to search for target status %s", targetStatusID)
targetStatus := &gtsmodel.Status{}
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
func (p *processor) Get(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
targetStatus, err := p.db.GetStatusByID(targetStatusID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
}
l.Tracef("going to search for target account %s", targetStatus.AccountID)
targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(targetStatus.AccountID, targetAccount); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching target account %s: %s", targetStatus.AccountID, err))
if targetStatus.Account == nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
}
l.Trace("going to see if status is visible")
visible, err := p.filter.StatusVisible(targetStatus, account) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
}
if !visible {
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
}
var boostOfStatus *gtsmodel.Status
if targetStatus.BoostOfID != "" {
boostOfStatus = &gtsmodel.Status{}
if err := p.db.GetByID(targetStatus.BoostOfID, boostOfStatus); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error fetching boosted status %s: %s", targetStatus.BoostOfID, err))
}
}
mastoStatus, err := p.tc.StatusToMasto(targetStatus, account)
mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
}
return mastoStatus, nil
}

View file

@ -10,27 +10,19 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
func (p *processor) Unboost(account *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
l := p.log.WithField("func", "Unboost")
l.Tracef("going to search for target status %s", targetStatusID)
targetStatus := &gtsmodel.Status{}
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
func (p *processor) Unboost(requestingAccount *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
targetStatus, err := p.db.GetStatusByID(targetStatusID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
}
l.Tracef("going to search for target account %s", targetStatus.AccountID)
targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(targetStatus.AccountID, targetAccount); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching target account %s: %s", targetStatus.AccountID, err))
if targetStatus.Account == nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
}
l.Trace("going to see if status is visible")
visible, err := p.filter.StatusVisible(targetStatus, account)
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
}
if !visible {
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
}
@ -46,7 +38,7 @@ func (p *processor) Unboost(account *gtsmodel.Account, application *gtsmodel.App
},
{
Key: "account_id",
Value: account.ID,
Value: requestingAccount.ID,
},
}
err = p.db.GetWhere(where, gtsBoost)
@ -71,22 +63,23 @@ func (p *processor) Unboost(account *gtsmodel.Account, application *gtsmodel.App
}
// pin some stuff onto the boost while we have it out of the db
gtsBoost.Account = requestingAccount
gtsBoost.BoostOf = targetStatus
gtsBoost.BoostOf.Account = targetAccount
gtsBoost.BoostOfAccount = targetAccount
gtsBoost.Account = account
gtsBoost.BoostOfAccount = targetStatus.Account
gtsBoost.BoostOf.Account = targetStatus.Account
// send it back to the processor for async processing
p.fromClientAPI <- gtsmodel.FromClientAPI{
APObjectType: gtsmodel.ActivityStreamsAnnounce,
APActivityType: gtsmodel.ActivityStreamsUndo,
GTSModel: gtsBoost,
OriginAccount: account,
TargetAccount: targetAccount,
OriginAccount: requestingAccount,
TargetAccount: targetStatus.Account,
}
}
mastoStatus, err := p.tc.StatusToMasto(targetStatus, account)
mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
}

View file

@ -10,26 +10,19 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
func (p *processor) Unfave(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
l := p.log.WithField("func", "StatusUnfave")
l.Tracef("going to search for target status %s", targetStatusID)
targetStatus := &gtsmodel.Status{}
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
func (p *processor) Unfave(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
targetStatus, err := p.db.GetStatusByID(targetStatusID)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
}
l.Tracef("going to search for target account %s", targetStatus.AccountID)
targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(targetStatus.AccountID, targetAccount); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching target account %s: %s", targetStatus.AccountID, err))
if targetStatus.Account == nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
}
l.Trace("going to see if status is visible")
visible, err := p.filter.StatusVisible(targetStatus, account)
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
}
if !visible {
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
}
@ -38,7 +31,7 @@ func (p *processor) Unfave(account *gtsmodel.Account, targetStatusID string) (*a
var toUnfave bool
gtsFave := &gtsmodel.StatusFave{}
err = p.db.GetWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: account.ID}}, gtsFave)
err = p.db.GetWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: requestingAccount.ID}}, gtsFave)
if err == nil {
// we have a fave
toUnfave = true
@ -54,7 +47,7 @@ func (p *processor) Unfave(account *gtsmodel.Account, targetStatusID string) (*a
if toUnfave {
// we had a fave, so take some action to get rid of it
if err := p.db.DeleteWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: account.ID}}, gtsFave); err != nil {
if err := p.db.DeleteWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: requestingAccount.ID}}, gtsFave); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error unfaveing status: %s", err))
}
@ -63,12 +56,12 @@ func (p *processor) Unfave(account *gtsmodel.Account, targetStatusID string) (*a
APObjectType: gtsmodel.ActivityStreamsLike,
APActivityType: gtsmodel.ActivityStreamsUndo,
GTSModel: gtsFave,
OriginAccount: account,
TargetAccount: targetAccount,
OriginAccount: requestingAccount,
TargetAccount: targetStatus.Account,
}
}
mastoStatus, err := p.tc.StatusToMasto(targetStatus, account)
mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount)
if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
}

View file

@ -119,7 +119,7 @@ func (p *processor) ProcessReplyToID(form *apimodel.AdvancedStatusCreateForm, th
return fmt.Errorf("status with id %s not replyable: %s", form.InReplyToID, err)
}
// check if a block exists
if blocked, err := p.db.Blocked(thisAccountID, repliedAccount.ID); err != nil {
if blocked, err := p.db.Blocked(thisAccountID, repliedAccount.ID, true); err != nil {
if err != db.ErrNoEntries {
return fmt.Errorf("status with id %s not replyable: %s", form.InReplyToID, err)
}
@ -156,8 +156,8 @@ func (p *processor) ProcessMediaIDs(form *apimodel.AdvancedStatusCreateForm, thi
gtsMediaAttachments = append(gtsMediaAttachments, a)
attachments = append(attachments, a.ID)
}
status.GTSMediaAttachments = gtsMediaAttachments
status.Attachments = attachments
status.Attachments = gtsMediaAttachments
status.AttachmentIDs = attachments
return nil
}
@ -192,9 +192,9 @@ func (p *processor) ProcessMentions(form *apimodel.AdvancedStatusCreateForm, acc
menchies = append(menchies, menchie.ID)
}
// add full populated gts menchies to the status for passing them around conveniently
status.GTSMentions = gtsMenchies
status.Mentions = gtsMenchies
// add just the ids of the mentioned accounts to the status for putting in the db
status.Mentions = menchies
status.MentionIDs = menchies
return nil
}
@ -211,9 +211,9 @@ func (p *processor) ProcessTags(form *apimodel.AdvancedStatusCreateForm, account
tags = append(tags, tag.ID)
}
// add full populated gts tags to the status for passing them around conveniently
status.GTSTags = gtsTags
status.Tags = gtsTags
// add just the ids of the used tags to the status for putting in the db
status.Tags = tags
status.TagIDs = tags
return nil
}
@ -227,9 +227,9 @@ func (p *processor) ProcessEmojis(form *apimodel.AdvancedStatusCreateForm, accou
emojis = append(emojis, e.ID)
}
// add full populated gts emojis to the status for passing them around conveniently
status.GTSEmojis = gtsEmojis
status.Emojis = gtsEmojis
// add just the ids of the used emojis to the status for putting in the db
status.Emojis = emojis
status.EmojiIDs = emojis
return nil
}
@ -252,9 +252,9 @@ func (p *processor) ProcessContent(form *apimodel.AdvancedStatusCreateForm, acco
var formatted string
switch form.Format {
case apimodel.StatusFormatPlain:
formatted = p.formatter.FromPlain(content, status.GTSMentions, status.GTSTags)
formatted = p.formatter.FromPlain(content, status.Mentions, status.Tags)
case apimodel.StatusFormatMarkdown:
formatted = p.formatter.FromMarkdown(content, status.GTSMentions, status.GTSTags)
formatted = p.formatter.FromMarkdown(content, status.Mentions, status.Tags)
default:
return fmt.Errorf("format %s not recognised as a valid status format", form.Format)
}

View file

@ -91,19 +91,19 @@ func (suite *UtilTestSuite) TestProcessMentions1() {
err := suite.status.ProcessMentions(form, creatingAccount.ID, status)
assert.NoError(suite.T(), err)
assert.Len(suite.T(), status.GTSMentions, 1)
newMention := status.GTSMentions[0]
assert.Len(suite.T(), status.Mentions, 1)
newMention := status.Mentions[0]
assert.Equal(suite.T(), mentionedAccount.ID, newMention.TargetAccountID)
assert.Equal(suite.T(), creatingAccount.ID, newMention.OriginAccountID)
assert.Equal(suite.T(), creatingAccount.URI, newMention.OriginAccountURI)
assert.Equal(suite.T(), status.ID, newMention.StatusID)
assert.Equal(suite.T(), fmt.Sprintf("@%s@%s", mentionedAccount.Username, mentionedAccount.Domain), newMention.NameString)
assert.Equal(suite.T(), mentionedAccount.URI, newMention.MentionedAccountURI)
assert.Equal(suite.T(), mentionedAccount.URL, newMention.MentionedAccountURL)
assert.NotNil(suite.T(), newMention.GTSAccount)
assert.Equal(suite.T(), mentionedAccount.URI, newMention.TargetAccountURI)
assert.Equal(suite.T(), mentionedAccount.URL, newMention.TargetAccountURL)
assert.NotNil(suite.T(), newMention.OriginAccount)
assert.Len(suite.T(), status.Mentions, 1)
assert.Equal(suite.T(), newMention.ID, status.Mentions[0])
assert.Len(suite.T(), status.MentionIDs, 1)
assert.Equal(suite.T(), newMention.ID, status.MentionIDs[0])
}
func (suite *UtilTestSuite) TestProcessContentFull1() {
@ -232,19 +232,19 @@ func (suite *UtilTestSuite) TestProcessMentions2() {
err := suite.status.ProcessMentions(form, creatingAccount.ID, status)
assert.NoError(suite.T(), err)
assert.Len(suite.T(), status.GTSMentions, 1)
newMention := status.GTSMentions[0]
assert.Len(suite.T(), status.Mentions, 1)
newMention := status.Mentions[0]
assert.Equal(suite.T(), mentionedAccount.ID, newMention.TargetAccountID)
assert.Equal(suite.T(), creatingAccount.ID, newMention.OriginAccountID)
assert.Equal(suite.T(), creatingAccount.URI, newMention.OriginAccountURI)
assert.Equal(suite.T(), status.ID, newMention.StatusID)
assert.Equal(suite.T(), fmt.Sprintf("@%s@%s", mentionedAccount.Username, mentionedAccount.Domain), newMention.NameString)
assert.Equal(suite.T(), mentionedAccount.URI, newMention.MentionedAccountURI)
assert.Equal(suite.T(), mentionedAccount.URL, newMention.MentionedAccountURL)
assert.NotNil(suite.T(), newMention.GTSAccount)
assert.Equal(suite.T(), mentionedAccount.URI, newMention.TargetAccountURI)
assert.Equal(suite.T(), mentionedAccount.URL, newMention.TargetAccountURL)
assert.NotNil(suite.T(), newMention.OriginAccount)
assert.Len(suite.T(), status.Mentions, 1)
assert.Equal(suite.T(), newMention.ID, status.Mentions[0])
assert.Len(suite.T(), status.MentionIDs, 1)
assert.Equal(suite.T(), newMention.ID, status.MentionIDs[0])
}
func (suite *UtilTestSuite) TestProcessContentFull2() {

View file

@ -93,9 +93,9 @@ func (f *formatter) ReplaceMentions(in string, mentions []*gtsmodel.Mention) str
// make sure we have a target account, either by getting one pinned on the mention,
// or by pulling it from the database
var targetAccount *gtsmodel.Account
if menchie.GTSAccount != nil {
if menchie.OriginAccount != nil {
// got it from the mention
targetAccount = menchie.GTSAccount
targetAccount = menchie.OriginAccount
} else {
a := &gtsmodel.Account{}
if err := f.db.GetByID(menchie.TargetAccountID, a); err == nil {

View file

@ -188,22 +188,22 @@ func (c *converter) ASStatusToStatus(statusable ap.Statusable) (*gtsmodel.Status
// attachments to dereference and fetch later on (we don't do that here)
if attachments, err := ap.ExtractAttachments(statusable); err == nil {
status.GTSMediaAttachments = attachments
status.Attachments = attachments
}
// hashtags to dereference later on
if hashtags, err := ap.ExtractHashtags(statusable); err == nil {
status.GTSTags = hashtags
status.Tags = hashtags
}
// emojis to dereference and fetch later on
if emojis, err := ap.ExtractEmojis(statusable); err == nil {
status.GTSEmojis = emojis
status.Emojis = emojis
}
// mentions to dereference later on
if mentions, err := ap.ExtractMentions(statusable); err == nil {
status.GTSMentions = mentions
status.Mentions = mentions
}
// cw string for this status
@ -515,10 +515,10 @@ func (c *converter) ASAnnounceToStatus(announceable ap.Announceable) (*gtsmodel.
status.AccountURI = boostingAccount.URI
// these will all be wrapped in the boosted status so set them empty here
status.Attachments = []string{}
status.Tags = []string{}
status.Mentions = []string{}
status.Emojis = []string{}
status.AttachmentIDs = []string{}
status.TagIDs = []string{}
status.MentionIDs = []string{}
status.EmojiIDs = []string{}
// parse the visibility from the To and CC entries
var visibility gtsmodel.Visibility

View file

@ -54,10 +54,10 @@ func (c *converter) StatusToBoost(s *gtsmodel.Status, boostingAccount *gtsmodel.
InReplyToAccountID: "",
// these will all be wrapped in the boosted status so set them empty here
Attachments: []string{},
Tags: []string{},
Mentions: []string{},
Emojis: []string{},
AttachmentIDs: []string{},
TagIDs: []string{},
MentionIDs: []string{},
EmojiIDs: []string{},
// the below fields will be taken from the target status
Content: s.Content,

View file

@ -408,7 +408,7 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e
tagProp := streams.NewActivityStreamsTagProperty()
// tag -- mentions
for _, m := range s.GTSMentions {
for _, m := range s.Mentions {
asMention, err := c.MentionToAS(m)
if err != nil {
return nil, fmt.Errorf("StatusToAS: error converting mention to AS mention: %s", err)
@ -441,10 +441,10 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e
switch s.Visibility {
case gtsmodel.VisibilityDirect:
// if DIRECT, then only mentioned users should be added to TO, and nothing to CC
for _, m := range s.GTSMentions {
iri, err := url.Parse(m.GTSAccount.URI)
for _, m := range s.Mentions {
iri, err := url.Parse(m.OriginAccount.URI)
if err != nil {
return nil, fmt.Errorf("StatusToAS: error parsing uri %s: %s", m.GTSAccount.URI, err)
return nil, fmt.Errorf("StatusToAS: error parsing uri %s: %s", m.OriginAccount.URI, err)
}
toProp.AppendIRI(iri)
}
@ -453,10 +453,10 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e
case gtsmodel.VisibilityFollowersOnly:
// if FOLLOWERS ONLY then we want to add followers to TO, and mentions to CC
toProp.AppendIRI(authorFollowersURI)
for _, m := range s.GTSMentions {
iri, err := url.Parse(m.GTSAccount.URI)
for _, m := range s.Mentions {
iri, err := url.Parse(m.OriginAccount.URI)
if err != nil {
return nil, fmt.Errorf("StatusToAS: error parsing uri %s: %s", m.GTSAccount.URI, err)
return nil, fmt.Errorf("StatusToAS: error parsing uri %s: %s", m.OriginAccount.URI, err)
}
ccProp.AppendIRI(iri)
}
@ -464,10 +464,10 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e
// if UNLOCKED, we want to add followers to TO, and public and mentions to CC
toProp.AppendIRI(authorFollowersURI)
ccProp.AppendIRI(publicURI)
for _, m := range s.GTSMentions {
iri, err := url.Parse(m.GTSAccount.URI)
for _, m := range s.Mentions {
iri, err := url.Parse(m.OriginAccount.URI)
if err != nil {
return nil, fmt.Errorf("StatusToAS: error parsing uri %s: %s", m.GTSAccount.URI, err)
return nil, fmt.Errorf("StatusToAS: error parsing uri %s: %s", m.OriginAccount.URI, err)
}
ccProp.AppendIRI(iri)
}
@ -475,10 +475,10 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e
// if PUBLIC, we want to add public to TO, and followers and mentions to CC
toProp.AppendIRI(publicURI)
ccProp.AppendIRI(authorFollowersURI)
for _, m := range s.GTSMentions {
iri, err := url.Parse(m.GTSAccount.URI)
for _, m := range s.Mentions {
iri, err := url.Parse(m.OriginAccount.URI)
if err != nil {
return nil, fmt.Errorf("StatusToAS: error parsing uri %s: %s", m.GTSAccount.URI, err)
return nil, fmt.Errorf("StatusToAS: error parsing uri %s: %s", m.OriginAccount.URI, err)
}
ccProp.AppendIRI(iri)
}
@ -496,7 +496,7 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e
// attachment
attachmentProp := streams.NewActivityStreamsAttachmentProperty()
for _, a := range s.GTSMediaAttachments {
for _, a := range s.Attachments {
doc, err := c.AttachmentToAS(a)
if err != nil {
return nil, fmt.Errorf("StatusToAS: error converting attachment: %s", err)
@ -565,12 +565,12 @@ func (c *converter) FollowToAS(f *gtsmodel.Follow, originAccount *gtsmodel.Accou
}
func (c *converter) MentionToAS(m *gtsmodel.Mention) (vocab.ActivityStreamsMention, error) {
if m.GTSAccount == nil {
if m.OriginAccount == nil {
a := &gtsmodel.Account{}
if err := c.db.GetWhere([]db.Where{{Key: "target_account_id", Value: m.TargetAccountID}}, a); err != nil {
return nil, fmt.Errorf("MentionToAS: error getting target account from db: %s", err)
}
m.GTSAccount = a
m.OriginAccount = a
}
// create the mention
@ -578,21 +578,21 @@ func (c *converter) MentionToAS(m *gtsmodel.Mention) (vocab.ActivityStreamsMenti
// href -- this should be the URI of the mentioned user
hrefProp := streams.NewActivityStreamsHrefProperty()
hrefURI, err := url.Parse(m.GTSAccount.URI)
hrefURI, err := url.Parse(m.OriginAccount.URI)
if err != nil {
return nil, fmt.Errorf("MentionToAS: error parsing uri %s: %s", m.GTSAccount.URI, err)
return nil, fmt.Errorf("MentionToAS: error parsing uri %s: %s", m.OriginAccount.URI, err)
}
hrefProp.SetIRI(hrefURI)
mention.SetActivityStreamsHref(hrefProp)
// name -- this should be the namestring of the mentioned user, something like @whatever@example.org
var domain string
if m.GTSAccount.Domain == "" {
if m.OriginAccount.Domain == "" {
domain = c.config.AccountDomain
} else {
domain = m.GTSAccount.Domain
domain = m.OriginAccount.Domain
}
username := m.GTSAccount.Username
username := m.OriginAccount.Username
nameString := fmt.Sprintf("@%s@%s", username, domain)
nameProp := streams.NewActivityStreamsNameProperty()
nameProp.AppendXMLSchemaString(nameString)

View file

@ -357,8 +357,8 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode
mastoAttachments := []model.Attachment{}
// the status might already have some gts attachments on it if it's not been pulled directly from the database
// if so, we can directly convert the gts attachments into masto ones
if s.GTSMediaAttachments != nil {
for _, gtsAttachment := range s.GTSMediaAttachments {
if s.Attachments != nil {
for _, gtsAttachment := range s.Attachments {
mastoAttachment, err := c.AttachmentToMasto(gtsAttachment)
if err != nil {
return nil, fmt.Errorf("error converting attachment with id %s: %s", gtsAttachment.ID, err)
@ -368,7 +368,7 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode
// the status doesn't have gts attachments on it, but it does have attachment IDs
// in this case, we need to pull the gts attachments from the db to convert them into masto ones
} else {
for _, a := range s.Attachments {
for _, a := range s.AttachmentIDs {
gtsAttachment := &gtsmodel.MediaAttachment{}
if err := c.db.GetByID(a, gtsAttachment); err != nil {
return nil, fmt.Errorf("error getting attachment with id %s: %s", a, err)
@ -384,8 +384,8 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode
mastoMentions := []model.Mention{}
// the status might already have some gts mentions on it if it's not been pulled directly from the database
// if so, we can directly convert the gts mentions into masto ones
if s.GTSMentions != nil {
for _, gtsMention := range s.GTSMentions {
if s.Mentions != nil {
for _, gtsMention := range s.Mentions {
mastoMention, err := c.MentionToMasto(gtsMention)
if err != nil {
return nil, fmt.Errorf("error converting mention with id %s: %s", gtsMention.ID, err)
@ -395,7 +395,7 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode
// the status doesn't have gts mentions on it, but it does have mention IDs
// in this case, we need to pull the gts mentions from the db to convert them into masto ones
} else {
for _, m := range s.Mentions {
for _, m := range s.MentionIDs {
gtsMention := &gtsmodel.Mention{}
if err := c.db.GetByID(m, gtsMention); err != nil {
return nil, fmt.Errorf("error getting mention with id %s: %s", m, err)
@ -411,8 +411,8 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode
mastoTags := []model.Tag{}
// the status might already have some gts tags on it if it's not been pulled directly from the database
// if so, we can directly convert the gts tags into masto ones
if s.GTSTags != nil {
for _, gtsTag := range s.GTSTags {
if s.Tags != nil {
for _, gtsTag := range s.Tags {
mastoTag, err := c.TagToMasto(gtsTag)
if err != nil {
return nil, fmt.Errorf("error converting tag with id %s: %s", gtsTag.ID, err)
@ -422,7 +422,7 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode
// the status doesn't have gts tags on it, but it does have tag IDs
// in this case, we need to pull the gts tags from the db to convert them into masto ones
} else {
for _, t := range s.Tags {
for _, t := range s.TagIDs {
gtsTag := &gtsmodel.Tag{}
if err := c.db.GetByID(t, gtsTag); err != nil {
return nil, fmt.Errorf("error getting tag with id %s: %s", t, err)
@ -438,8 +438,8 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode
mastoEmojis := []model.Emoji{}
// the status might already have some gts emojis on it if it's not been pulled directly from the database
// if so, we can directly convert the gts emojis into masto ones
if s.GTSEmojis != nil {
for _, gtsEmoji := range s.GTSEmojis {
if s.Emojis != nil {
for _, gtsEmoji := range s.Emojis {
mastoEmoji, err := c.EmojiToMasto(gtsEmoji)
if err != nil {
return nil, fmt.Errorf("error converting emoji with id %s: %s", gtsEmoji.ID, err)
@ -449,7 +449,7 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode
// the status doesn't have gts emojis on it, but it does have emoji IDs
// in this case, we need to pull the gts emojis from the db to convert them into masto ones
} else {
for _, e := range s.Emojis {
for _, e := range s.EmojiIDs {
gtsEmoji := &gtsmodel.Emoji{}
if err := c.db.GetByID(e, gtsEmoji); err != nil {
return nil, fmt.Errorf("error getting emoji with id %s: %s", e, err)
@ -609,46 +609,46 @@ func (c *converter) RelationshipToMasto(r *gtsmodel.Relationship) (*model.Relati
func (c *converter) NotificationToMasto(n *gtsmodel.Notification) (*model.Notification, error) {
if n.GTSTargetAccount == nil {
if n.TargetAccount == nil {
tAccount := &gtsmodel.Account{}
if err := c.db.GetByID(n.TargetAccountID, tAccount); err != nil {
return nil, fmt.Errorf("NotificationToMasto: error getting target account with id %s from the db: %s", n.TargetAccountID, err)
}
n.GTSTargetAccount = tAccount
n.TargetAccount = tAccount
}
if n.GTSOriginAccount == nil {
if n.OriginAccount == nil {
ogAccount := &gtsmodel.Account{}
if err := c.db.GetByID(n.OriginAccountID, ogAccount); err != nil {
return nil, fmt.Errorf("NotificationToMasto: error getting origin account with id %s from the db: %s", n.OriginAccountID, err)
}
n.GTSOriginAccount = ogAccount
n.OriginAccount = ogAccount
}
mastoAccount, err := c.AccountToMastoPublic(n.GTSOriginAccount)
mastoAccount, err := c.AccountToMastoPublic(n.OriginAccount)
if err != nil {
return nil, fmt.Errorf("NotificationToMasto: error converting account to masto: %s", err)
}
var mastoStatus *model.Status
if n.StatusID != "" {
if n.GTSStatus == nil {
if n.Status == nil {
status := &gtsmodel.Status{}
if err := c.db.GetByID(n.StatusID, status); err != nil {
return nil, fmt.Errorf("NotificationToMasto: error getting status with id %s from the db: %s", n.StatusID, err)
}
n.GTSStatus = status
n.Status = status
}
if n.GTSStatus.Account == nil {
if n.GTSStatus.AccountID == n.GTSTargetAccount.ID {
n.GTSStatus.Account = n.GTSTargetAccount
} else if n.GTSStatus.AccountID == n.GTSOriginAccount.ID {
n.GTSStatus.Account = n.GTSOriginAccount
if n.Status.Account == nil {
if n.Status.AccountID == n.TargetAccount.ID {
n.Status.Account = n.TargetAccount
} else if n.Status.AccountID == n.OriginAccount.ID {
n.Status.Account = n.OriginAccount
}
}
var err error
mastoStatus, err = c.StatusToMasto(n.GTSStatus, nil)
mastoStatus, err = c.StatusToMasto(n.Status, nil)
if err != nil {
return nil, fmt.Errorf("NotificationToMasto: error converting status to masto: %s", err)
}

View file

@ -102,7 +102,7 @@ func (f *filter) StatusVisible(targetStatus *gtsmodel.Status, requestingAccount
// At this point we have a populated targetAccount, targetStatus, and requestingAccount, so we can check for blocks and whathaveyou
// First check if a block exists directly between the target account (which authored the status) and the requesting account.
if blocked, err := f.db.Blocked(targetAccount.ID, requestingAccount.ID); err != nil {
if blocked, err := f.db.Blocked(targetAccount.ID, requestingAccount.ID, true); err != nil {
l.Debugf("something went wrong figuring out if the accounts have a block: %s", err)
return false, err
} else if blocked {
@ -113,7 +113,7 @@ func (f *filter) StatusVisible(targetStatus *gtsmodel.Status, requestingAccount
// status replies to account id
if relevantAccounts.ReplyToAccount != nil && relevantAccounts.ReplyToAccount.ID != requestingAccount.ID {
if blocked, err := f.db.Blocked(relevantAccounts.ReplyToAccount.ID, requestingAccount.ID); err != nil {
if blocked, err := f.db.Blocked(relevantAccounts.ReplyToAccount.ID, requestingAccount.ID, true); err != nil {
return false, err
} else if blocked {
l.Trace("a block exists between requesting account and reply to account")
@ -135,7 +135,7 @@ func (f *filter) StatusVisible(targetStatus *gtsmodel.Status, requestingAccount
// status boosts accounts id
if relevantAccounts.BoostedStatusAuthor != nil {
if blocked, err := f.db.Blocked(relevantAccounts.BoostedStatusAuthor.ID, requestingAccount.ID); err != nil {
if blocked, err := f.db.Blocked(relevantAccounts.BoostedStatusAuthor.ID, requestingAccount.ID, true); err != nil {
return false, err
} else if blocked {
l.Trace("a block exists between requesting account and boosted account")
@ -145,7 +145,7 @@ func (f *filter) StatusVisible(targetStatus *gtsmodel.Status, requestingAccount
// status boosts a reply to account id
if relevantAccounts.BoostedReplyToAccount != nil {
if blocked, err := f.db.Blocked(relevantAccounts.BoostedReplyToAccount.ID, requestingAccount.ID); err != nil {
if blocked, err := f.db.Blocked(relevantAccounts.BoostedReplyToAccount.ID, requestingAccount.ID, true); err != nil {
return false, err
} else if blocked {
l.Trace("a block exists between requesting account and boosted reply to account")
@ -155,7 +155,7 @@ func (f *filter) StatusVisible(targetStatus *gtsmodel.Status, requestingAccount
// status mentions accounts
for _, a := range relevantAccounts.MentionedAccounts {
if blocked, err := f.db.Blocked(a.ID, requestingAccount.ID); err != nil {
if blocked, err := f.db.Blocked(a.ID, requestingAccount.ID, true); err != nil {
return false, err
} else if blocked {
l.Trace("a block exists between requesting account and a mentioned account")
@ -165,7 +165,7 @@ func (f *filter) StatusVisible(targetStatus *gtsmodel.Status, requestingAccount
// boost mentions accounts
for _, a := range relevantAccounts.BoostedMentionedAccounts {
if blocked, err := f.db.Blocked(a.ID, requestingAccount.ID); err != nil {
if blocked, err := f.db.Blocked(a.ID, requestingAccount.ID, true); err != nil {
return false, err
} else if blocked {
l.Trace("a block exists between requesting account and a boosted mentioned account")

View file

@ -13,28 +13,71 @@ func (f *filter) pullRelevantAccountsFromStatus(targetStatus *gtsmodel.Status) (
BoostedMentionedAccounts: []*gtsmodel.Account{},
}
// get the author account
// get the author account if it's not set on the status already
if targetStatus.Account == nil {
statusAuthor := &gtsmodel.Account{}
if err := f.db.GetByID(targetStatus.AccountID, statusAuthor); err != nil {
statusAuthor, err := f.db.GetAccountByID(targetStatus.AccountID)
if err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting statusAuthor with id %s: %s", targetStatus.AccountID, err)
}
targetStatus.Account = statusAuthor
}
accounts.StatusAuthor = targetStatus.Account
// get the replied to account from the status and add it to the pile
if targetStatus.InReplyToAccountID != "" {
repliedToAccount := &gtsmodel.Account{}
if err := f.db.GetByID(targetStatus.InReplyToAccountID, repliedToAccount); err != nil {
// get the replied to account if it's not set on the status already
if targetStatus.InReplyToAccountID != "" && targetStatus.InReplyToAccount == nil {
repliedToAccount, err := f.db.GetAccountByID(targetStatus.InReplyToAccountID)
if err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting repliedToAcount with id %s: %s", targetStatus.InReplyToAccountID, err)
}
accounts.ReplyToAccount = repliedToAccount
targetStatus.InReplyToAccount = repliedToAccount
}
accounts.ReplyToAccount = targetStatus.InReplyToAccount
// get the boosted status if it's not set on the status already
if targetStatus.BoostOfID != "" && targetStatus.BoostOf == nil {
boostedStatus, err := f.db.GetStatusByID(targetStatus.BoostOfID)
if err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting boostedStatus with id %s: %s", targetStatus.BoostOfID, err)
}
targetStatus.BoostOf = boostedStatus
}
// get the boosted account if it's not set on the status already
if targetStatus.BoostOfAccountID != "" && targetStatus.BoostOfAccount == nil {
if targetStatus.BoostOf != nil && targetStatus.BoostOf.Account != nil {
targetStatus.BoostOfAccount = targetStatus.BoostOf.Account
} else {
boostedAccount, err := f.db.GetAccountByID(targetStatus.BoostOfAccountID)
if err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting boostOfAccount with id %s: %s", targetStatus.BoostOfAccountID, err)
}
targetStatus.BoostOfAccount = boostedAccount
}
}
accounts.BoostedStatusAuthor = targetStatus.BoostOfAccount
if targetStatus.BoostOf != nil {
// the boosted status might be a reply to another account so we should get that too
if targetStatus.BoostOf.InReplyToAccountID != "" && targetStatus.BoostOf.InReplyToAccount == nil {
boostOfInReplyToAccount, err := f.db.GetAccountByID(targetStatus.BoostOf.InReplyToAccountID)
if err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting boostOfInReplyToAccount with id %s: %s", targetStatus.BoostOf.InReplyToAccountID, err)
}
targetStatus.BoostOf.InReplyToAccount = boostOfInReplyToAccount
}
// now get all accounts with IDs that are mentioned in the status
if targetStatus.BoostOf.MentionIDs != nil && targetStatus.BoostOf.Mentions == nil {
mentions, err := f.db.GetMentions(targetStatus.BoostOf.MentionIDs)
if err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting mentions from boostOf status: %s", err)
}
targetStatus.BoostOf.Mentions = mentions
}
}
// now get all accounts with IDs that are mentioned in the status
for _, mentionID := range targetStatus.Mentions {
for _, mentionID := range targetStatus.MentionIDs {
mention := &gtsmodel.Mention{}
if err := f.db.GetByID(mentionID, mention); err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting mention with id %s: %s", mentionID, err)
@ -47,43 +90,6 @@ func (f *filter) pullRelevantAccountsFromStatus(targetStatus *gtsmodel.Status) (
accounts.MentionedAccounts = append(accounts.MentionedAccounts, mentionedAccount)
}
// get the boosted account from the status and add it to the pile
if targetStatus.BoostOfID != "" {
// retrieve the boosted status first
boostedStatus := &gtsmodel.Status{}
if err := f.db.GetByID(targetStatus.BoostOfID, boostedStatus); err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting boostedStatus with id %s: %s", targetStatus.BoostOfID, err)
}
boostedAccount := &gtsmodel.Account{}
if err := f.db.GetByID(boostedStatus.AccountID, boostedAccount); err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting boostedAccount with id %s: %s", boostedStatus.AccountID, err)
}
accounts.BoostedStatusAuthor = boostedAccount
// the boosted status might be a reply to another account so we should get that too
if boostedStatus.InReplyToAccountID != "" {
boostedStatusRepliedToAccount := &gtsmodel.Account{}
if err := f.db.GetByID(boostedStatus.InReplyToAccountID, boostedStatusRepliedToAccount); err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting boostedStatusRepliedToAccount with id %s: %s", boostedStatus.InReplyToAccountID, err)
}
accounts.BoostedReplyToAccount = boostedStatusRepliedToAccount
}
// now get all accounts with IDs that are mentioned in the status
for _, mentionID := range boostedStatus.Mentions {
mention := &gtsmodel.Mention{}
if err := f.db.GetByID(mentionID, mention); err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting boosted mention with id %s: %s", mentionID, err)
}
mentionedAccount := &gtsmodel.Account{}
if err := f.db.GetByID(mention.TargetAccountID, mentionedAccount); err != nil {
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting boosted mentioned account: %s", err)
}
accounts.BoostedMentionedAccounts = append(accounts.BoostedMentionedAccounts, mentionedAccount)
}
}
return accounts, nil
}

View file

@ -793,10 +793,10 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
URI: "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
URL: "http://localhost:8080/@admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
Content: "hello world! #welcome ! first post on the instance :rainbow: !",
Attachments: []string{"01F8MH6NEM8D7527KZAECTCR76"},
Tags: []string{"01F8MHA1A2NF9MJ3WCCQ3K8BSZ"},
Mentions: []string{},
Emojis: []string{"01F8MH9H8E4VG3KDYJR9EGPXCQ"},
AttachmentIDs: []string{"01F8MH6NEM8D7527KZAECTCR76"},
TagIDs: []string{"01F8MHA1A2NF9MJ3WCCQ3K8BSZ"},
MentionIDs: []string{},
EmojiIDs: []string{"01F8MH9H8E4VG3KDYJR9EGPXCQ"},
CreatedAt: time.Now().Add(-71 * time.Hour),
UpdatedAt: time.Now().Add(-71 * time.Hour),
Local: true,
@ -917,7 +917,7 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
URI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MH82FYRXD2RC6108DAJ5HB",
URL: "http://localhost:8080/@the_mighty_zork/statuses/01F8MH82FYRXD2RC6108DAJ5HB",
Content: "here's a little gif of trent",
Attachments: []string{"01F8MH7TDVANYKWVE8VVKFPJTJ"},
AttachmentIDs: []string{"01F8MH7TDVANYKWVE8VVKFPJTJ"},
CreatedAt: time.Now().Add(-1 * time.Hour),
UpdatedAt: time.Now().Add(-1 * time.Hour),
Local: true,
@ -942,7 +942,7 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
URI: "http://localhost:8080/users/the_mighty_zork/statuses/01FCTA44PW9H1TB328S9AQXKDS",
URL: "http://localhost:8080/@the_mighty_zork/statuses/01FCTA44PW9H1TB328S9AQXKDS",
Content: "hi!",
Attachments: []string{},
AttachmentIDs: []string{},
CreatedAt: time.Now().Add(-1 * time.Minute),
UpdatedAt: time.Now().Add(-1 * time.Minute),
Local: true,
@ -1127,8 +1127,8 @@ func NewTestMentions() map[string]*gtsmodel.Mention {
OriginAccountURI: "http://localhost:8080/users/the_mighty_zork",
TargetAccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX",
NameString: "@foss_satan@fossbros-anonymous.io",
MentionedAccountURI: "http://fossbros-anonymous.io/users/foss_satan",
MentionedAccountURL: "http://fossbros-anonymous.io/@foss_satan",
TargetAccountURI: "http://fossbros-anonymous.io/users/foss_satan",
TargetAccountURL: "http://fossbros-anonymous.io/@foss_satan",
},
}
}