mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-12-30 01:06:15 -06:00
more fiddling
This commit is contained in:
parent
15153ee0c8
commit
a3322b2bf3
65 changed files with 712 additions and 508 deletions
|
|
@ -581,7 +581,7 @@ func ExtractMention(i Mentionable) (*gtsmodel.Mention, error) {
|
||||||
if hrefProp == nil || !hrefProp.IsIRI() {
|
if hrefProp == nil || !hrefProp.IsIRI() {
|
||||||
return nil, errors.New("no href prop")
|
return nil, errors.New("no href prop")
|
||||||
}
|
}
|
||||||
mention.MentionedAccountURI = hrefProp.GetIRI().String()
|
mention.TargetAccountURI = hrefProp.GetIRI().String()
|
||||||
return mention, nil
|
return mention, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
package db
|
||||||
|
|
||||||
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
|
|
|
||||||
|
|
@ -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
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -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
|
package db
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
|
|
@ -11,6 +29,10 @@ type Basic interface {
|
||||||
// For implementations that don't use tables, this can just return nil.
|
// For implementations that don't use tables, this can just return nil.
|
||||||
DropTable(i interface{}) DBError
|
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.
|
// 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.
|
// If the database implementation doesn't need to be stopped, this can just return nil.
|
||||||
Stop(ctx context.Context) DBError
|
Stop(ctx context.Context) DBError
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ type DB interface {
|
||||||
Admin
|
Admin
|
||||||
Basic
|
Basic
|
||||||
Instance
|
Instance
|
||||||
|
Mention
|
||||||
Notification
|
Notification
|
||||||
Relationship
|
Relationship
|
||||||
Status
|
Status
|
||||||
|
|
|
||||||
|
|
@ -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
|
package db
|
||||||
|
|
||||||
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
|
|
|
||||||
29
internal/db/mention.go
Normal file
29
internal/db/mention.go
Normal 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)
|
||||||
|
}
|
||||||
|
|
@ -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
|
package db
|
||||||
|
|
||||||
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
func (b *basicDB) IsHealthy(ctx context.Context) db.DBError {
|
||||||
return b.conn.Ping(ctx)
|
return b.conn.Ping(ctx)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
77
internal/db/pg/mention.go
Normal file
77
internal/db/pg/mention.go
Normal 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 := >smodel.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
|
||||||
|
}
|
||||||
|
|
@ -44,6 +44,7 @@ type postgresService struct {
|
||||||
db.Admin
|
db.Admin
|
||||||
db.Basic
|
db.Basic
|
||||||
db.Instance
|
db.Instance
|
||||||
|
db.Mention
|
||||||
db.Notification
|
db.Notification
|
||||||
db.Relationship
|
db.Relationship
|
||||||
db.Status
|
db.Status
|
||||||
|
|
@ -116,6 +117,12 @@ func NewPostgresService(ctx context.Context, c *config.Config, log *logrus.Logge
|
||||||
log: log,
|
log: log,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
},
|
},
|
||||||
|
Mention: &mentionDB{
|
||||||
|
config: c,
|
||||||
|
conn: conn,
|
||||||
|
log: log,
|
||||||
|
cancel: cancel,
|
||||||
|
},
|
||||||
Relationship: &relationshipDB{
|
Relationship: &relationshipDB{
|
||||||
config: c,
|
config: c,
|
||||||
conn: conn,
|
conn: conn,
|
||||||
|
|
@ -318,9 +325,9 @@ func (ps *postgresService) MentionStringsToMentions(targetAccounts []string, ori
|
||||||
OriginAccountURI: ogAccount.URI,
|
OriginAccountURI: ogAccount.URI,
|
||||||
TargetAccountID: mentionedAccount.ID,
|
TargetAccountID: mentionedAccount.ID,
|
||||||
NameString: a,
|
NameString: a,
|
||||||
MentionedAccountURI: mentionedAccount.URI,
|
TargetAccountURI: mentionedAccount.URI,
|
||||||
MentionedAccountURL: mentionedAccount.URL,
|
TargetAccountURL: mentionedAccount.URL,
|
||||||
GTSAccount: mentionedAccount,
|
OriginAccount: mentionedAccount,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return menchies, nil
|
return menchies, nil
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-pg/pg/v10"
|
"github.com/go-pg/pg/v10"
|
||||||
|
"github.com/go-pg/pg/v10/orm"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
|
|
@ -36,21 +37,41 @@ type relationshipDB struct {
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *relationshipDB) Blocked(account1 string, account2 string) (bool, db.DBError) {
|
func (r *relationshipDB) newBlockQ(block *gtsmodel.Block) *orm.Query {
|
||||||
// TODO: check domain blocks as well
|
return r.conn.Model(block).
|
||||||
var blocked bool
|
Relation("Account").
|
||||||
if err := r.conn.Model(>smodel.Block{}).
|
Relation("TargetAccount")
|
||||||
Where("account_id = ?", account1).Where("target_account_id = ?", account2).
|
}
|
||||||
WhereOr("target_account_id = ?", account1).Where("account_id = ?", account2).
|
|
||||||
Select(); err != nil {
|
func (r *relationshipDB) processResponse(block *gtsmodel.Block, err error) (*gtsmodel.Block, db.DBError) {
|
||||||
if err == pg.ErrNoRows {
|
switch err {
|
||||||
blocked = false
|
case pg.ErrNoRows:
|
||||||
return blocked, nil
|
return nil, db.ErrNoEntries
|
||||||
|
case nil:
|
||||||
|
return block, nil
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return blocked, err
|
}
|
||||||
|
|
||||||
|
func (r *relationshipDB) Blocked(account1 string, account2 string, eitherDirection bool) (bool, db.DBError) {
|
||||||
|
q := r.conn.Model(>smodel.Block{}).Where("account_id = ?", account1).Where("target_account_id = ?", account2)
|
||||||
|
|
||||||
|
if eitherDirection {
|
||||||
|
q = q.WhereOr("target_account_id = ?", account1).Where("account_id = ?", account2)
|
||||||
}
|
}
|
||||||
blocked = true
|
|
||||||
return blocked, nil
|
return q.Exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *relationshipDB) GetBlock(account1 string, account2 string) (*gtsmodel.Block, db.DBError) {
|
||||||
|
block := >smodel.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) {
|
func (r *relationshipDB) GetRelationship(requestingAccount string, targetAccount string) (*gtsmodel.Relationship, db.DBError) {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@ type statusDB struct {
|
||||||
|
|
||||||
func (s *statusDB) newStatusQ(status *gtsmodel.Status) *orm.Query {
|
func (s *statusDB) newStatusQ(status *gtsmodel.Status) *orm.Query {
|
||||||
return s.conn.Model(status).
|
return s.conn.Model(status).
|
||||||
|
Relation("Attachments").
|
||||||
|
Relation("Tags").
|
||||||
|
Relation("Mentions").
|
||||||
|
Relation("Emojis").
|
||||||
Relation("Account").
|
Relation("Account").
|
||||||
Relation("InReplyTo").
|
Relation("InReplyTo").
|
||||||
Relation("InReplyToAccount").
|
Relation("InReplyToAccount").
|
||||||
|
|
@ -48,7 +52,7 @@ func (s *statusDB) newStatusQ(status *gtsmodel.Status) *orm.Query {
|
||||||
Relation("CreatedWithApplication")
|
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 {
|
switch err {
|
||||||
case pg.ErrNoRows:
|
case pg.ErrNoRows:
|
||||||
return nil, db.ErrNoEntries
|
return nil, db.ErrNoEntries
|
||||||
|
|
@ -65,7 +69,7 @@ func (s *statusDB) GetStatusByID(id string) (*gtsmodel.Status, db.DBError) {
|
||||||
q := s.newStatusQ(status).
|
q := s.newStatusQ(status).
|
||||||
Where("status.id = ?", id)
|
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) {
|
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).
|
q := s.newStatusQ(status).
|
||||||
Where("LOWER(status.uri) = LOWER(?)", uri)
|
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) {
|
func (s *statusDB) StatusParents(status *gtsmodel.Status, onlyDirect bool) ([]*gtsmodel.Status, db.DBError) {
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,18 @@ func (suite *PGStandardTestSuite) TestGetStatusByURI() {
|
||||||
suite.Nil(status.InReplyTo)
|
suite.Nil(status.InReplyTo)
|
||||||
suite.Nil(status.InReplyToAccount)
|
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) {
|
func TestStatusTestSuite(t *testing.T) {
|
||||||
suite.Run(t, new(PGStandardTestSuite))
|
suite.Run(t, new(PGStandardTestSuite))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
package db
|
||||||
|
|
||||||
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
|
|
||||||
type Relationship interface {
|
type Relationship interface {
|
||||||
// Blocked checks whether a block exists in eiher direction between two accounts.
|
// Blocked checks whether account 1 has a block in place against block2.
|
||||||
// That is, it returns true if account1 blocks account2, OR if account2 blocks account1.
|
// If eitherDirection is true, then the function returns true if account1 blocks account2, OR if account2 blocks account1.
|
||||||
Blocked(account1 string, account2 string) (bool, DBError)
|
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 retrieves the relationship of the targetAccount to the requestingAccount.
|
||||||
GetRelationship(requestingAccount string, targetAccount string) (*gtsmodel.Relationship, DBError)
|
GetRelationship(requestingAccount string, targetAccount string) (*gtsmodel.Relationship, DBError)
|
||||||
|
|
|
||||||
|
|
@ -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
|
package db
|
||||||
|
|
||||||
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
|
|
|
||||||
|
|
@ -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
|
package db
|
||||||
|
|
||||||
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
import "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,7 @@ func (d *deref) populateStatusFields(status *gtsmodel.Status, requestingUsername
|
||||||
// * the remote URL (a.RemoteURL)
|
// * the remote URL (a.RemoteURL)
|
||||||
// This should be enough to pass along to the media processor.
|
// This should be enough to pass along to the media processor.
|
||||||
attachmentIDs := []string{}
|
attachmentIDs := []string{}
|
||||||
for _, a := range status.GTSMediaAttachments {
|
for _, a := range status.Attachments {
|
||||||
l.Tracef("dereferencing attachment: %+v", a)
|
l.Tracef("dereferencing attachment: %+v", a)
|
||||||
|
|
||||||
// it might have been processed elsewhere so check first if it's already in the database or not
|
// 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)
|
attachmentIDs = append(attachmentIDs, deferencedAttachment.ID)
|
||||||
}
|
}
|
||||||
status.Attachments = attachmentIDs
|
status.AttachmentIDs = attachmentIDs
|
||||||
|
|
||||||
// 2. Hashtags
|
// 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.
|
// We should dereference any accounts mentioned here which we don't have in our db yet, by their URI.
|
||||||
mentions := []string{}
|
mentions := []string{}
|
||||||
for _, m := range status.GTSMentions {
|
for _, m := range status.Mentions {
|
||||||
|
|
||||||
if m.ID != "" {
|
if m.ID != "" {
|
||||||
continue
|
continue
|
||||||
|
|
@ -331,9 +331,9 @@ func (d *deref) populateStatusFields(status *gtsmodel.Status, requestingUsername
|
||||||
}
|
}
|
||||||
m.ID = mID
|
m.ID = mID
|
||||||
|
|
||||||
uri, err := url.Parse(m.MentionedAccountURI)
|
uri, err := url.Parse(m.TargetAccountURI)
|
||||||
if err != nil {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -353,7 +353,7 @@ func (d *deref) populateStatusFields(status *gtsmodel.Status, requestingUsername
|
||||||
}
|
}
|
||||||
mentions = append(mentions, m.ID)
|
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
|
// status has replyToURI but we don't have an ID yet for the status it replies to
|
||||||
if status.InReplyToURI != "" && status.InReplyToID == "" {
|
if status.InReplyToURI != "" && status.InReplyToID == "" {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ type DomainBlock struct {
|
||||||
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// Account ID of the creator of this block
|
// Account ID of the creator of this block
|
||||||
CreatedByAccountID string `pg:"type:CHAR(26),notnull"`
|
CreatedByAccountID string `pg:"type:CHAR(26),notnull"`
|
||||||
|
CreatedByAccount *Account `pg:"rel:belongs-to"`
|
||||||
// Private comment on this block, viewable to admins
|
// Private comment on this block, viewable to admins
|
||||||
PrivateComment string
|
PrivateComment string
|
||||||
// Public comment on this block, viewable (optionally) by everyone
|
// Public comment on this block, viewable (optionally) by everyone
|
||||||
|
|
|
||||||
|
|
@ -32,4 +32,5 @@ type EmailDomainBlock struct {
|
||||||
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// Account ID of the creator of this block
|
// Account ID of the creator of this block
|
||||||
CreatedByAccountID string `pg:"type:CHAR(26),notnull"`
|
CreatedByAccountID string `pg:"type:CHAR(26),notnull"`
|
||||||
|
CreatedByAccount *Account `pg:"rel:belongs-to"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,4 +74,5 @@ type Emoji struct {
|
||||||
VisibleInPicker bool `pg:",notnull,default:true"`
|
VisibleInPicker bool `pg:",notnull,default:true"`
|
||||||
// In which emoji category is this emoji visible?
|
// 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"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,10 @@ type Follow struct {
|
||||||
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// Who does this follow belong to?
|
// Who does this follow belong to?
|
||||||
AccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
|
AccountID string `pg:"type:CHAR(26),unique:srctarget,notnull"`
|
||||||
|
Account *Account `pg:"rel:belongs-to"`
|
||||||
// Who does AccountID follow?
|
// Who does AccountID follow?
|
||||||
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?
|
// Does this follow also want to see reblogs and not just posts?
|
||||||
ShowReblogs bool `pg:"default:true"`
|
ShowReblogs bool `pg:"default:true"`
|
||||||
// What is the activitypub URI of this follow?
|
// What is the activitypub URI of this follow?
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,10 @@ type FollowRequest struct {
|
||||||
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// Who does this follow request originate from?
|
// 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?
|
// 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?
|
// Does this follow also want to see reblogs and not just posts?
|
||||||
ShowReblogs bool `pg:"default:true"`
|
ShowReblogs bool `pg:"default:true"`
|
||||||
// What is the activitypub URI of this follow request?
|
// What is the activitypub URI of this follow request?
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ type MediaAttachment struct {
|
||||||
FileMeta FileMeta
|
FileMeta FileMeta
|
||||||
// To which account does this attachment belong
|
// To which account does this attachment belong
|
||||||
AccountID string `pg:"type:CHAR(26),notnull"`
|
AccountID string `pg:"type:CHAR(26),notnull"`
|
||||||
|
Account *Account `pg:"rel:belongs-to"`
|
||||||
// Description of the attachment (for screenreaders)
|
// Description of the attachment (for screenreaders)
|
||||||
Description string
|
Description string
|
||||||
// To which scheduled status does this attachment belong
|
// To which scheduled status does this attachment belong
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,19 @@ type Mention struct {
|
||||||
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
|
ID string `pg:"type:CHAR(26),pk,notnull,unique"`
|
||||||
// ID of the status this mention originates from
|
// ID of the status this mention originates from
|
||||||
StatusID string `pg:"type:CHAR(26),notnull"`
|
StatusID string `pg:"type:CHAR(26),notnull"`
|
||||||
|
Status *Status `pg:"rel:belongs-to"`
|
||||||
// When was this mention created?
|
// When was this mention created?
|
||||||
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// When was this mention last updated?
|
// When was this mention last updated?
|
||||||
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// What's the internal account ID of the originator of the mention?
|
// What's the internal account ID of the originator of the mention?
|
||||||
OriginAccountID string `pg:"type:CHAR(26),notnull"`
|
OriginAccountID string `pg:"type:CHAR(26),notnull"`
|
||||||
|
OriginAccount *Account `pg:"rel:has-one"`
|
||||||
// What's the AP URI of the originator of the mention?
|
// What's the AP URI of the originator of the mention?
|
||||||
OriginAccountURI string `pg:",notnull"`
|
OriginAccountURI string `pg:",notnull"`
|
||||||
// What's the internal account ID of the mention target?
|
// What's the internal account ID of the mention target?
|
||||||
TargetAccountID string `pg:"type:CHAR(26),notnull"`
|
TargetAccountID string `pg:"type:CHAR(26),notnull"`
|
||||||
|
TargetAccount *Account `pg:"rel:has-one"`
|
||||||
// Prevent this mention from generating a notification?
|
// Prevent this mention from generating a notification?
|
||||||
Silent bool
|
Silent bool
|
||||||
|
|
||||||
|
|
@ -52,14 +55,14 @@ type Mention struct {
|
||||||
//
|
//
|
||||||
// This will not be put in the database, it's just for convenience.
|
// This will not be put in the database, it's just for convenience.
|
||||||
NameString string `pg:"-"`
|
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.
|
// This will not be put in the database, it's just for convenience.
|
||||||
MentionedAccountURI string `pg:"-"`
|
TargetAccountURI string `pg:"-"`
|
||||||
// MentionedAccountURL is the web url of the user mentioned.
|
// TargetAccountURL is the web url of the user mentioned.
|
||||||
//
|
//
|
||||||
// This will not be put in the database, it's just for convenience.
|
// 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.
|
// A pointer to the gtsmodel account of the mentioned account.
|
||||||
GTSAccount *Account `pg:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,23 +30,15 @@ type Notification struct {
|
||||||
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// Which account does this notification target (ie., who will receive the notification?)
|
// 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?
|
// 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?
|
// 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?
|
// Has this notification been read already?
|
||||||
Read bool
|
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.
|
// NotificationType describes the reason/type of this notification.
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,17 @@ type Status struct {
|
||||||
// the html-formatted content of this status
|
// the html-formatted content of this status
|
||||||
Content string
|
Content string
|
||||||
// Database IDs of any media attachments associated with this status
|
// 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
|
// 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
|
// 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
|
// 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?
|
// when was this status created?
|
||||||
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// when was this status updated?
|
// when was this status updated?
|
||||||
|
|
@ -85,25 +89,6 @@ type Status struct {
|
||||||
Text string
|
Text string
|
||||||
// Has this status been pinned by its owner?
|
// Has this status been pinned by its owner?
|
||||||
Pinned bool
|
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.
|
// Visibility represents the visibility granularity of a status.
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,10 @@ type StatusBookmark struct {
|
||||||
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// id of the account that created ('did') the bookmarking
|
// id of the account that created ('did') the bookmarking
|
||||||
AccountID string `pg:"type:CHAR(26),notnull"`
|
AccountID string `pg:"type:CHAR(26),notnull"`
|
||||||
|
Account *Account `pg:"rel:belongs-to"`
|
||||||
// id the account owning the bookmarked status
|
// id the account owning the bookmarked status
|
||||||
TargetAccountID string `pg:"type:CHAR(26),notnull"`
|
TargetAccountID string `pg:"type:CHAR(26),notnull"`
|
||||||
|
TargetAccount *Account `pg:"rel:has-one"`
|
||||||
// database id of the status that has been bookmarked
|
// database id of the status that has been bookmarked
|
||||||
StatusID string `pg:"type:CHAR(26),notnull"`
|
StatusID string `pg:"type:CHAR(26),notnull"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ type StatusFave struct {
|
||||||
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// id of the account that created ('did') the fave
|
// id of the account that created ('did') the fave
|
||||||
AccountID string `pg:"type:CHAR(26),notnull"`
|
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
|
// id the account owning the faved status
|
||||||
TargetAccountID string `pg:"type:CHAR(26),notnull"`
|
TargetAccountID string `pg:"type:CHAR(26),notnull"`
|
||||||
TargetAccount *Account `pg:"rel:has-one"`
|
TargetAccount *Account `pg:"rel:has-one"`
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,11 @@ type StatusMute struct {
|
||||||
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"`
|
||||||
// id of the account that created ('did') the mute
|
// id of the account that created ('did') the mute
|
||||||
AccountID string `pg:"type:CHAR(26),notnull"`
|
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)
|
// id the account owning the muted status (can be the same as accountID)
|
||||||
TargetAccountID string `pg:"type:CHAR(26),notnull"`
|
TargetAccountID string `pg:"type:CHAR(26),notnull"`
|
||||||
|
TargetAccount *Account `pg:"rel:has-one"`
|
||||||
// database id of the status that has been muted
|
// database id of the status that has been muted
|
||||||
StatusID string `pg:"type:CHAR(26),notnull"`
|
StatusID string `pg:"type:CHAR(26),notnull"`
|
||||||
|
Status *Status `pg:"rel:has-one"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ type User struct {
|
||||||
Email string `pg:"default:null,unique"`
|
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)
|
// 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
|
// 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"`
|
EncryptedPassword string `pg:",notnull"`
|
||||||
|
|
||||||
|
|
@ -69,6 +70,7 @@ type User struct {
|
||||||
Locale string
|
Locale string
|
||||||
// Which application id created this user? See gtsmodel.Application
|
// 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
|
// When did we last contact this user
|
||||||
LastEmailedAt time.Time `pg:"type:timestamp"`
|
LastEmailedAt time.Time `pg:"type:timestamp"`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,24 +31,20 @@ import (
|
||||||
|
|
||||||
func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) {
|
func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) {
|
||||||
// make sure the target account actually exists in our db
|
// make sure the target account actually exists in our db
|
||||||
targetAcct := >smodel.Account{}
|
targetAccount, err := p.db.GetAccountByID(targetAccountID)
|
||||||
if err := p.db.GetByID(targetAccountID, targetAcct); err != nil {
|
if err != nil {
|
||||||
if err == db.ErrNoEntries {
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("BlockCreate: error getting account %s from the db: %s", targetAccountID, err))
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("BlockCreate: account %s not found in the db: %s", targetAccountID, err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if requestingAccount already blocks target account, we don't need to do anything
|
// if requestingAccount already blocks target account, we don't need to do anything
|
||||||
block := >smodel.Block{}
|
if blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID, false); err != nil {
|
||||||
if err := p.db.GetWhere([]db.Where{
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("BlockCreate: error checking existence of block: %s", err))
|
||||||
{Key: "account_id", Value: requestingAccount.ID},
|
} else if blocked {
|
||||||
{Key: "target_account_id", Value: targetAccountID},
|
|
||||||
}, block); err == nil {
|
|
||||||
// block already exists, just return relationship
|
|
||||||
return p.RelationshipGet(requestingAccount, targetAccountID)
|
return p.RelationshipGet(requestingAccount, targetAccountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// make the block
|
// make the block
|
||||||
|
block := >smodel.Block{}
|
||||||
newBlockID, err := id.NewULID()
|
newBlockID, err := id.NewULID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
|
|
@ -57,7 +53,7 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou
|
||||||
block.AccountID = requestingAccount.ID
|
block.AccountID = requestingAccount.ID
|
||||||
block.Account = requestingAccount
|
block.Account = requestingAccount
|
||||||
block.TargetAccountID = targetAccountID
|
block.TargetAccountID = targetAccountID
|
||||||
block.TargetAccount = targetAcct
|
block.TargetAccount = targetAccount
|
||||||
block.URI = util.GenerateURIForBlock(requestingAccount.Username, p.config.Protocol, p.config.Host, newBlockID)
|
block.URI = util.GenerateURIForBlock(requestingAccount.Username, p.config.Protocol, p.config.Host, newBlockID)
|
||||||
|
|
||||||
// whack it in the database
|
// whack it in the database
|
||||||
|
|
@ -123,7 +119,7 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou
|
||||||
URI: frURI,
|
URI: frURI,
|
||||||
},
|
},
|
||||||
OriginAccount: requestingAccount,
|
OriginAccount: requestingAccount,
|
||||||
TargetAccount: targetAcct,
|
TargetAccount: targetAccount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,7 +134,7 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou
|
||||||
URI: fURI,
|
URI: fURI,
|
||||||
},
|
},
|
||||||
OriginAccount: requestingAccount,
|
OriginAccount: requestingAccount,
|
||||||
TargetAccount: targetAcct,
|
TargetAccount: targetAccount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,7 +144,7 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou
|
||||||
APActivityType: gtsmodel.ActivityStreamsCreate,
|
APActivityType: gtsmodel.ActivityStreamsCreate,
|
||||||
GTSModel: block,
|
GTSModel: block,
|
||||||
OriginAccount: requestingAccount,
|
OriginAccount: requestingAccount,
|
||||||
TargetAccount: targetAcct,
|
TargetAccount: targetAccount,
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.RelationshipGet(requestingAccount, targetAccountID)
|
return p.RelationshipGet(requestingAccount, targetAccountID)
|
||||||
|
|
|
||||||
|
|
@ -31,38 +31,33 @@ import (
|
||||||
|
|
||||||
func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) {
|
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
|
// 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 blocked, err := p.db.Blocked(requestingAccount.ID, form.ID, true); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
} else if blocked {
|
||||||
if blocked {
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts"))
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("accountfollowcreate: block exists between accounts"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the target account actually exists in our db
|
// make sure the target account actually exists in our db
|
||||||
targetAcct := >smodel.Account{}
|
targetAcct, err := p.db.GetAccountByID(form.ID)
|
||||||
if err := p.db.GetByID(form.ID, targetAcct); err != nil {
|
if err != nil {
|
||||||
if err == db.ErrNoEntries {
|
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.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
|
// check if a follow exists already
|
||||||
follows, err := p.db.Follows(requestingAccount, targetAcct)
|
if follows, err := p.db.Follows(requestingAccount, targetAcct); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error checking follow in db: %s", err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error checking follow in db: %s", err))
|
||||||
}
|
} else if follows {
|
||||||
if follows {
|
|
||||||
// already follows so just return the relationship
|
// already follows so just return the relationship
|
||||||
return p.RelationshipGet(requestingAccount, form.ID)
|
return p.RelationshipGet(requestingAccount, form.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if a follow exists already
|
// check if a follow request exists already
|
||||||
followRequested, err := p.db.FollowRequested(requestingAccount, targetAcct)
|
if followRequested, err := p.db.FollowRequested(requestingAccount, targetAcct); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error checking follow request in db: %s", err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error checking follow request in db: %s", err))
|
||||||
}
|
} else if followRequested {
|
||||||
if followRequested {
|
|
||||||
// already follow requested so just return the relationship
|
// already follow requested so just return the relationship
|
||||||
return p.RelationshipGet(requestingAccount, form.ID)
|
return p.RelationshipGet(requestingAccount, form.ID)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func (p *processor) Get(requestingAccount *gtsmodel.Account, targetAccountID str
|
||||||
var blocked bool
|
var blocked bool
|
||||||
var err error
|
var err error
|
||||||
if requestingAccount != nil {
|
if requestingAccount != nil {
|
||||||
blocked, err = p.db.Blocked(requestingAccount.ID, targetAccountID)
|
blocked, err = p.db.Blocked(requestingAccount.ID, targetAccountID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error checking account block: %s", err)
|
return nil, fmt.Errorf("error checking account block: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) FollowersGet(requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) {
|
func (p *processor) FollowersGet(requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) {
|
||||||
blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID)
|
if blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID, true); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
} else if blocked {
|
||||||
|
|
||||||
if blocked {
|
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts"))
|
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 {
|
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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) FollowingGet(requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) {
|
func (p *processor) FollowingGet(requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) {
|
||||||
blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID)
|
if blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID, true); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
} else if blocked {
|
||||||
|
|
||||||
if blocked {
|
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts"))
|
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 {
|
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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
func (p *processor) StatusesGet(requestingAccount *gtsmodel.Account, targetAccountID string, limit int, excludeReplies bool, maxID string, pinnedOnly bool, mediaOnly bool) ([]apimodel.Status, gtserror.WithCode) {
|
||||||
targetAccount := >smodel.Account{}
|
if blocked, err := p.db.Blocked(requestingAccount.ID, targetAccountID, true); err != nil {
|
||||||
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))
|
|
||||||
}
|
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
|
} else if blocked {
|
||||||
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts"))
|
||||||
}
|
}
|
||||||
|
|
||||||
apiStatuses := []apimodel.Status{}
|
apiStatuses := []apimodel.Status{}
|
||||||
|
|
||||||
statuses, err := p.db.GetAccountStatuses(targetAccountID, limit, excludeReplies, maxID, pinnedOnly, mediaOnly)
|
statuses, err := p.db.GetAccountStatuses(targetAccountID, limit, excludeReplies, maxID, pinnedOnly, mediaOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == db.ErrNoEntries {
|
if err == db.ErrNoEntries {
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,9 @@ import (
|
||||||
|
|
||||||
func (p *processor) BlockRemove(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) {
|
func (p *processor) BlockRemove(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) {
|
||||||
// make sure the target account actually exists in our db
|
// make sure the target account actually exists in our db
|
||||||
targetAcct := >smodel.Account{}
|
targetAccount, err := p.db.GetAccountByID(targetAccountID)
|
||||||
if err := p.db.GetByID(targetAccountID, targetAcct); err != nil {
|
if err != nil {
|
||||||
if err == db.ErrNoEntries {
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("BlockCreate: error getting account %s from the db: %s", targetAccountID, err))
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("BlockRemove: account %s not found in the db: %s", targetAccountID, err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if a block exists, and remove it if it does (storing the URI for later)
|
// 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},
|
{Key: "target_account_id", Value: targetAccountID},
|
||||||
}, block); err == nil {
|
}, block); err == nil {
|
||||||
block.Account = requestingAccount
|
block.Account = requestingAccount
|
||||||
block.TargetAccount = targetAcct
|
block.TargetAccount = targetAccount
|
||||||
if err := p.db.DeleteByID(block.ID, >smodel.Block{}); err != nil {
|
if err := p.db.DeleteByID(block.ID, >smodel.Block{}); err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("BlockRemove: error removing block from db: %s", err))
|
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,
|
APActivityType: gtsmodel.ActivityStreamsUndo,
|
||||||
GTSModel: block,
|
GTSModel: block,
|
||||||
OriginAccount: requestingAccount,
|
OriginAccount: requestingAccount,
|
||||||
TargetAccount: targetAcct,
|
TargetAccount: targetAccount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
|
|
||||||
func (p *processor) FollowRemove(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) {
|
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
|
// 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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ func (p *processor) GetFediUser(ctx context.Context, requestedUsername string, r
|
||||||
return nil, gtserror.NewErrorNotAuthorized(err)
|
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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +107,7 @@ func (p *processor) GetFediFollowers(ctx context.Context, requestedUsername stri
|
||||||
return nil, gtserror.NewErrorNotAuthorized(err)
|
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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +152,7 @@ func (p *processor) GetFediFollowing(ctx context.Context, requestedUsername stri
|
||||||
return nil, gtserror.NewErrorNotAuthorized(err)
|
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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +199,7 @@ func (p *processor) GetFediStatus(ctx context.Context, requestedUsername string,
|
||||||
|
|
||||||
// authorize the request:
|
// authorize the request:
|
||||||
// 1. check if a block exists between the requester and the requestee
|
// 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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
@ -259,7 +259,7 @@ func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername
|
||||||
|
|
||||||
// authorize the request:
|
// authorize the request:
|
||||||
// 1. check if a block exists between the requester and the requestee
|
// 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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,14 +192,14 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete all attachments for this status
|
// delete all attachments for this status
|
||||||
for _, a := range statusToDelete.Attachments {
|
for _, a := range statusToDelete.AttachmentIDs {
|
||||||
if err := p.mediaProcessor.Delete(a); err != nil {
|
if err := p.mediaProcessor.Delete(a); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete all mentions for this status
|
// delete all mentions for this status
|
||||||
for _, m := range statusToDelete.Mentions {
|
for _, m := range statusToDelete.MentionIDs {
|
||||||
if err := p.db.DeleteByID(m, >smodel.Mention{}); err != nil {
|
if err := p.db.DeleteByID(m, >smodel.Mention{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,35 +30,35 @@ import (
|
||||||
|
|
||||||
func (p *processor) notifyStatus(status *gtsmodel.Status) error {
|
func (p *processor) notifyStatus(status *gtsmodel.Status) error {
|
||||||
// if there are no mentions in this status then just bail
|
// if there are no mentions in this status then just bail
|
||||||
if len(status.Mentions) == 0 {
|
if len(status.MentionIDs) == 0 {
|
||||||
return nil
|
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
|
// there are mentions but they're not fully populated on the status yet so do this
|
||||||
menchies := []*gtsmodel.Mention{}
|
menchies := []*gtsmodel.Mention{}
|
||||||
for _, m := range status.Mentions {
|
for _, m := range status.MentionIDs {
|
||||||
gtsm := >smodel.Mention{}
|
gtsm := >smodel.Mention{}
|
||||||
if err := p.db.GetByID(m, gtsm); err != nil {
|
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)
|
return fmt.Errorf("notifyStatus: error getting mention with id %s from the db: %s", m, err)
|
||||||
}
|
}
|
||||||
menchies = append(menchies, gtsm)
|
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
|
// 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
|
// 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 := >smodel.Account{}
|
a := >smodel.Account{}
|
||||||
if err := p.db.GetByID(m.TargetAccountID, a); err != nil {
|
if err := p.db.GetByID(m.TargetAccountID, a); err != nil {
|
||||||
// we don't have the account or there's been an error
|
// 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)
|
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
|
// not a local account so skip it
|
||||||
continue
|
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)
|
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)
|
return fmt.Errorf("notifyStatus: error streaming notification to account: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,14 +164,14 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete all attachments for this status
|
// delete all attachments for this status
|
||||||
for _, a := range statusToDelete.Attachments {
|
for _, a := range statusToDelete.AttachmentIDs {
|
||||||
if err := p.mediaProcessor.Delete(a); err != nil {
|
if err := p.mediaProcessor.Delete(a); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete all mentions for this status
|
// delete all mentions for this status
|
||||||
for _, m := range statusToDelete.Mentions {
|
for _, m := range statusToDelete.MentionIDs {
|
||||||
if err := p.db.DeleteByID(m, >smodel.Mention{}); err != nil {
|
if err := p.db.DeleteByID(m, >smodel.Mention{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
// make sure the requesting account and the media account don't block each other
|
||||||
if account != nil {
|
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 {
|
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))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("block status could not be established between accounts %s and %s: %s", form.AccountID, account.ID, err))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ func (p *processor) SearchGet(authed *oauth.Auth, searchQuery *apimodel.SearchQu
|
||||||
*/
|
*/
|
||||||
for _, foundAccount := range foundAccounts {
|
for _, foundAccount := range foundAccounts {
|
||||||
// make sure there's no block in either direction between the account and the requester
|
// 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
|
// all good, convert it and add it to the results
|
||||||
if acctMasto, err := p.tc.AccountToMastoPublic(foundAccount); err == nil && acctMasto != nil {
|
if acctMasto, err := p.tc.AccountToMastoPublic(foundAccount); err == nil && acctMasto != nil {
|
||||||
results.Accounts = append(results.Accounts, *acctMasto)
|
results.Accounts = append(results.Accounts, *acctMasto)
|
||||||
|
|
|
||||||
|
|
@ -9,31 +9,22 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) Boost(account *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
func (p *processor) Boost(requestingAccount *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
||||||
l := p.log.WithField("func", "StatusBoost")
|
targetStatus, err := p.db.GetStatusByID(targetStatusID)
|
||||||
|
if err != nil {
|
||||||
l.Tracef("going to search for target status %s", targetStatusID)
|
|
||||||
targetStatus := >smodel.Status{}
|
|
||||||
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
|
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
||||||
}
|
}
|
||||||
|
if targetStatus.Account == nil {
|
||||||
l.Tracef("going to search for target account %s", targetStatus.AccountID)
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
|
||||||
targetAccount := >smodel.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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Trace("going to see if status is visible")
|
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
|
||||||
visible, err := p.filter.StatusVisible(targetStatus, account)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !visible {
|
if !visible {
|
||||||
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
|
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetStatus.VisibilityAdvanced != nil {
|
if targetStatus.VisibilityAdvanced != nil {
|
||||||
if !targetStatus.VisibilityAdvanced.Boostable {
|
if !targetStatus.VisibilityAdvanced.Boostable {
|
||||||
return nil, gtserror.NewErrorForbidden(errors.New("status is not 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
|
// 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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
boostWrapperStatus.CreatedWithApplicationID = application.ID
|
boostWrapperStatus.CreatedWithApplicationID = application.ID
|
||||||
boostWrapperStatus.BoostOfAccount = targetAccount
|
boostWrapperStatus.BoostOfAccount = targetStatus.Account
|
||||||
|
|
||||||
// put the boost in the database
|
// put the boost in the database
|
||||||
if err := p.db.Put(boostWrapperStatus); err != nil {
|
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,
|
APObjectType: gtsmodel.ActivityStreamsAnnounce,
|
||||||
APActivityType: gtsmodel.ActivityStreamsCreate,
|
APActivityType: gtsmodel.ActivityStreamsCreate,
|
||||||
GTSModel: boostWrapperStatus,
|
GTSModel: boostWrapperStatus,
|
||||||
OriginAccount: account,
|
OriginAccount: requestingAccount,
|
||||||
TargetAccount: targetAccount,
|
TargetAccount: targetStatus.Account,
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the frontend representation of the new status to the submitter
|
// 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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,29 +9,21 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) BoostedBy(account *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) {
|
func (p *processor) BoostedBy(requestingAccount *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) {
|
||||||
l := p.log.WithField("func", "StatusBoostedBy")
|
targetStatus, err := p.db.GetStatusByID(targetStatusID)
|
||||||
|
|
||||||
l.Tracef("going to search for target status %s", targetStatusID)
|
|
||||||
targetStatus := >smodel.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 := >smodel.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)
|
|
||||||
if err != nil {
|
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 {
|
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
|
// 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
|
// filter the list so the user doesn't see accounts they blocked or which blocked them
|
||||||
filteredAccounts := []*gtsmodel.Account{}
|
filteredAccounts := []*gtsmodel.Account{}
|
||||||
for _, acc := range favingAccounts {
|
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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error checking blocks: %s", err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error checking blocks: %s", err))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,45 @@
|
||||||
package status
|
package status
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
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/gtserror"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"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{
|
context := &apimodel.Context{
|
||||||
Ancestors: []apimodel.Status{},
|
Ancestors: []apimodel.Status{},
|
||||||
Descendants: []apimodel.Status{},
|
Descendants: []apimodel.Status{},
|
||||||
}
|
}
|
||||||
|
|
||||||
targetStatus := >smodel.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)
|
parents, err := p.db.StatusParents(targetStatus, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, status := range parents {
|
for _, status := range parents {
|
||||||
if v, err := p.filter.StatusVisible(status, account); err == nil && v {
|
if v, err := p.filter.StatusVisible(status, requestingAccount); err == nil && v {
|
||||||
mastoStatus, err := p.tc.StatusToMasto(status, account)
|
mastoStatus, err := p.tc.StatusToMasto(status, requestingAccount)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
context.Ancestors = append(context.Ancestors, *mastoStatus)
|
context.Ancestors = append(context.Ancestors, *mastoStatus)
|
||||||
}
|
}
|
||||||
|
|
@ -57,8 +56,8 @@ func (p *processor) Context(account *gtsmodel.Account, targetStatusID string) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, status := range children {
|
for _, status := range children {
|
||||||
if v, err := p.filter.StatusVisible(status, account); err == nil && v {
|
if v, err := p.filter.StatusVisible(status, requestingAccount); err == nil && v {
|
||||||
mastoStatus, err := p.tc.StatusToMasto(status, account)
|
mastoStatus, err := p.tc.StatusToMasto(status, requestingAccount)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
context.Descendants = append(context.Descendants, *mastoStatus)
|
context.Descendants = append(context.Descendants, *mastoStatus)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
// 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.StatusID = newStatus.ID
|
||||||
a.UpdatedAt = time.Now()
|
a.UpdatedAt = time.Now()
|
||||||
if err := p.db.UpdateByID(a.ID, a); err != nil {
|
if err := p.db.UpdateByID(a.ID, a); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -5,36 +5,24 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
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/gtserror"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) Delete(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
func (p *processor) Delete(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
||||||
l := p.log.WithField("func", "StatusDelete")
|
targetStatus, err := p.db.GetStatusByID(targetStatusID)
|
||||||
l.Tracef("going to search for target status %s", targetStatusID)
|
if err != nil {
|
||||||
targetStatus := >smodel.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))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
||||||
}
|
}
|
||||||
// status is already gone
|
if targetStatus.Account == nil {
|
||||||
return nil, 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"))
|
return nil, gtserror.NewErrorForbidden(errors.New("status doesn't belong to requesting account"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var boostOfStatus *gtsmodel.Status
|
mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount)
|
||||||
if targetStatus.BoostOfID != "" {
|
|
||||||
boostOfStatus = >smodel.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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
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,
|
APObjectType: gtsmodel.ActivityStreamsNote,
|
||||||
APActivityType: gtsmodel.ActivityStreamsDelete,
|
APActivityType: gtsmodel.ActivityStreamsDelete,
|
||||||
GTSModel: targetStatus,
|
GTSModel: targetStatus,
|
||||||
OriginAccount: account,
|
OriginAccount: requestingAccount,
|
||||||
TargetAccount: account,
|
TargetAccount: requestingAccount,
|
||||||
}
|
}
|
||||||
|
|
||||||
return mastoStatus, nil
|
return mastoStatus, nil
|
||||||
|
|
|
||||||
|
|
@ -12,39 +12,22 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) Fave(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
func (p *processor) Fave(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
||||||
l := p.log.WithField("func", "StatusFave")
|
targetStatus, err := p.db.GetStatusByID(targetStatusID)
|
||||||
l.Tracef("going to search for target status %s", targetStatusID)
|
if err != nil {
|
||||||
targetStatus := >smodel.Status{}
|
|
||||||
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
|
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
||||||
}
|
}
|
||||||
|
if targetStatus.Account == nil {
|
||||||
l.Tracef("going to search for target account %s", targetStatus.AccountID)
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
|
||||||
targetAccount := >smodel.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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var boostOfStatus *gtsmodel.Status
|
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
|
||||||
if targetStatus.BoostOfID != "" {
|
|
||||||
boostOfStatus = >smodel.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
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !visible {
|
if !visible {
|
||||||
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
|
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// is the status faveable?
|
|
||||||
if targetStatus.VisibilityAdvanced != nil {
|
if targetStatus.VisibilityAdvanced != nil {
|
||||||
if !targetStatus.VisibilityAdvanced.Likeable {
|
if !targetStatus.VisibilityAdvanced.Likeable {
|
||||||
return nil, gtserror.NewErrorForbidden(errors.New("status is not faveable"))
|
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
|
// first check if the status is already faved, if so we don't need to do anything
|
||||||
newFave := true
|
newFave := true
|
||||||
gtsFave := >smodel.StatusFave{}
|
gtsFave := >smodel.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
|
// we already have a fave for this status
|
||||||
newFave = false
|
newFave = false
|
||||||
}
|
}
|
||||||
|
|
@ -68,13 +51,13 @@ func (p *processor) Fave(account *gtsmodel.Account, targetStatusID string) (*api
|
||||||
// we need to create a new fave in the database
|
// we need to create a new fave in the database
|
||||||
gtsFave := >smodel.StatusFave{
|
gtsFave := >smodel.StatusFave{
|
||||||
ID: thisFaveID,
|
ID: thisFaveID,
|
||||||
AccountID: account.ID,
|
AccountID: requestingAccount.ID,
|
||||||
TargetAccountID: targetAccount.ID,
|
Account: requestingAccount,
|
||||||
|
TargetAccountID: targetStatus.AccountID,
|
||||||
|
TargetAccount: targetStatus.Account,
|
||||||
StatusID: targetStatus.ID,
|
StatusID: targetStatus.ID,
|
||||||
URI: util.GenerateURIForLike(account.Username, p.config.Protocol, p.config.Host, thisFaveID),
|
|
||||||
Status: targetStatus,
|
Status: targetStatus,
|
||||||
TargetAccount: targetAccount,
|
URI: util.GenerateURIForLike(requestingAccount.Username, p.config.Protocol, p.config.Host, thisFaveID),
|
||||||
Account: account,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.db.Put(gtsFave); err != nil {
|
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,
|
APObjectType: gtsmodel.ActivityStreamsLike,
|
||||||
APActivityType: gtsmodel.ActivityStreamsCreate,
|
APActivityType: gtsmodel.ActivityStreamsCreate,
|
||||||
GTSModel: gtsFave,
|
GTSModel: gtsFave,
|
||||||
OriginAccount: account,
|
OriginAccount: requestingAccount,
|
||||||
TargetAccount: targetAccount,
|
TargetAccount: targetStatus.Account,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the mastodon representation of the target status
|
// 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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,27 +9,19 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) FavedBy(account *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) {
|
func (p *processor) FavedBy(requestingAccount *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) {
|
||||||
l := p.log.WithField("func", "StatusFavedBy")
|
targetStatus, err := p.db.GetStatusByID(targetStatusID)
|
||||||
|
if err != nil {
|
||||||
l.Tracef("going to search for target status %s", targetStatusID)
|
|
||||||
targetStatus := >smodel.Status{}
|
|
||||||
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
|
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
||||||
}
|
}
|
||||||
|
if targetStatus.Account == nil {
|
||||||
l.Tracef("going to search for target account %s", targetStatus.AccountID)
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
|
||||||
targetAccount := >smodel.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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Trace("going to see if status is visible")
|
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
|
||||||
visible, err := p.filter.StatusVisible(targetStatus, account)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !visible {
|
if !visible {
|
||||||
return nil, gtserror.NewErrorNotFound(errors.New("status is not 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
|
// filter the list so the user doesn't see accounts they blocked or which blocked them
|
||||||
filteredAccounts := []*gtsmodel.Account{}
|
filteredAccounts := []*gtsmodel.Account{}
|
||||||
for _, acc := range favingAccounts {
|
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 {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking blocks: %s", err))
|
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
|
// now we can return the masto representation of those accounts
|
||||||
mastoAccounts := []*apimodel.Account{}
|
mastoAccounts := []*apimodel.Account{}
|
||||||
for _, acc := range filteredAccounts {
|
for _, acc := range filteredAccounts {
|
||||||
|
|
|
||||||
|
|
@ -9,44 +9,27 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) Get(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
func (p *processor) Get(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
||||||
l := p.log.WithField("func", "StatusGet")
|
targetStatus, err := p.db.GetStatusByID(targetStatusID)
|
||||||
|
if err != nil {
|
||||||
l.Tracef("going to search for target status %s", targetStatusID)
|
|
||||||
targetStatus := >smodel.Status{}
|
|
||||||
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
|
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
||||||
}
|
}
|
||||||
|
if targetStatus.Account == nil {
|
||||||
l.Tracef("going to search for target account %s", targetStatus.AccountID)
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
|
||||||
targetAccount := >smodel.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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Trace("going to see if status is visible")
|
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
|
||||||
visible, err := p.filter.StatusVisible(targetStatus, account) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !visible {
|
if !visible {
|
||||||
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
|
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
|
||||||
}
|
}
|
||||||
|
|
||||||
var boostOfStatus *gtsmodel.Status
|
mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount)
|
||||||
if targetStatus.BoostOfID != "" {
|
|
||||||
boostOfStatus = >smodel.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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return mastoStatus, nil
|
return mastoStatus, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,27 +10,19 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) Unboost(account *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
func (p *processor) Unboost(requestingAccount *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
||||||
l := p.log.WithField("func", "Unboost")
|
targetStatus, err := p.db.GetStatusByID(targetStatusID)
|
||||||
|
if err != nil {
|
||||||
l.Tracef("going to search for target status %s", targetStatusID)
|
|
||||||
targetStatus := >smodel.Status{}
|
|
||||||
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
|
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
||||||
}
|
}
|
||||||
|
if targetStatus.Account == nil {
|
||||||
l.Tracef("going to search for target account %s", targetStatus.AccountID)
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
|
||||||
targetAccount := >smodel.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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Trace("going to see if status is visible")
|
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
|
||||||
visible, err := p.filter.StatusVisible(targetStatus, account)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !visible {
|
if !visible {
|
||||||
return nil, gtserror.NewErrorNotFound(errors.New("status is not 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",
|
Key: "account_id",
|
||||||
Value: account.ID,
|
Value: requestingAccount.ID,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err = p.db.GetWhere(where, gtsBoost)
|
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
|
// pin some stuff onto the boost while we have it out of the db
|
||||||
|
gtsBoost.Account = requestingAccount
|
||||||
|
|
||||||
gtsBoost.BoostOf = targetStatus
|
gtsBoost.BoostOf = targetStatus
|
||||||
gtsBoost.BoostOf.Account = targetAccount
|
gtsBoost.BoostOfAccount = targetStatus.Account
|
||||||
gtsBoost.BoostOfAccount = targetAccount
|
gtsBoost.BoostOf.Account = targetStatus.Account
|
||||||
gtsBoost.Account = account
|
|
||||||
|
|
||||||
// send it back to the processor for async processing
|
// send it back to the processor for async processing
|
||||||
p.fromClientAPI <- gtsmodel.FromClientAPI{
|
p.fromClientAPI <- gtsmodel.FromClientAPI{
|
||||||
APObjectType: gtsmodel.ActivityStreamsAnnounce,
|
APObjectType: gtsmodel.ActivityStreamsAnnounce,
|
||||||
APActivityType: gtsmodel.ActivityStreamsUndo,
|
APActivityType: gtsmodel.ActivityStreamsUndo,
|
||||||
GTSModel: gtsBoost,
|
GTSModel: gtsBoost,
|
||||||
OriginAccount: account,
|
OriginAccount: requestingAccount,
|
||||||
TargetAccount: targetAccount,
|
TargetAccount: targetStatus.Account,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mastoStatus, err := p.tc.StatusToMasto(targetStatus, account)
|
mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,26 +10,19 @@ import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) Unfave(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
func (p *processor) Unfave(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) {
|
||||||
l := p.log.WithField("func", "StatusUnfave")
|
targetStatus, err := p.db.GetStatusByID(targetStatusID)
|
||||||
l.Tracef("going to search for target status %s", targetStatusID)
|
if err != nil {
|
||||||
targetStatus := >smodel.Status{}
|
|
||||||
if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
|
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
|
||||||
}
|
}
|
||||||
|
if targetStatus.Account == nil {
|
||||||
l.Tracef("going to search for target account %s", targetStatus.AccountID)
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID))
|
||||||
targetAccount := >smodel.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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Trace("going to see if status is visible")
|
visible, err := p.filter.StatusVisible(targetStatus, requestingAccount)
|
||||||
visible, err := p.filter.StatusVisible(targetStatus, account)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !visible {
|
if !visible {
|
||||||
return nil, gtserror.NewErrorNotFound(errors.New("status is not 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
|
var toUnfave bool
|
||||||
|
|
||||||
gtsFave := >smodel.StatusFave{}
|
gtsFave := >smodel.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 {
|
if err == nil {
|
||||||
// we have a fave
|
// we have a fave
|
||||||
toUnfave = true
|
toUnfave = true
|
||||||
|
|
@ -54,7 +47,7 @@ func (p *processor) Unfave(account *gtsmodel.Account, targetStatusID string) (*a
|
||||||
|
|
||||||
if toUnfave {
|
if toUnfave {
|
||||||
// we had a fave, so take some action to get rid of it
|
// 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))
|
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,
|
APObjectType: gtsmodel.ActivityStreamsLike,
|
||||||
APActivityType: gtsmodel.ActivityStreamsUndo,
|
APActivityType: gtsmodel.ActivityStreamsUndo,
|
||||||
GTSModel: gtsFave,
|
GTSModel: gtsFave,
|
||||||
OriginAccount: account,
|
OriginAccount: requestingAccount,
|
||||||
TargetAccount: targetAccount,
|
TargetAccount: targetStatus.Account,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mastoStatus, err := p.tc.StatusToMasto(targetStatus, account)
|
mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
return fmt.Errorf("status with id %s not replyable: %s", form.InReplyToID, err)
|
||||||
}
|
}
|
||||||
// check if a block exists
|
// 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 {
|
if err != db.ErrNoEntries {
|
||||||
return fmt.Errorf("status with id %s not replyable: %s", form.InReplyToID, err)
|
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)
|
gtsMediaAttachments = append(gtsMediaAttachments, a)
|
||||||
attachments = append(attachments, a.ID)
|
attachments = append(attachments, a.ID)
|
||||||
}
|
}
|
||||||
status.GTSMediaAttachments = gtsMediaAttachments
|
status.Attachments = gtsMediaAttachments
|
||||||
status.Attachments = attachments
|
status.AttachmentIDs = attachments
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,9 +192,9 @@ func (p *processor) ProcessMentions(form *apimodel.AdvancedStatusCreateForm, acc
|
||||||
menchies = append(menchies, menchie.ID)
|
menchies = append(menchies, menchie.ID)
|
||||||
}
|
}
|
||||||
// add full populated gts menchies to the status for passing them around conveniently
|
// 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
|
// add just the ids of the mentioned accounts to the status for putting in the db
|
||||||
status.Mentions = menchies
|
status.MentionIDs = menchies
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,9 +211,9 @@ func (p *processor) ProcessTags(form *apimodel.AdvancedStatusCreateForm, account
|
||||||
tags = append(tags, tag.ID)
|
tags = append(tags, tag.ID)
|
||||||
}
|
}
|
||||||
// add full populated gts tags to the status for passing them around conveniently
|
// 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
|
// add just the ids of the used tags to the status for putting in the db
|
||||||
status.Tags = tags
|
status.TagIDs = tags
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,9 +227,9 @@ func (p *processor) ProcessEmojis(form *apimodel.AdvancedStatusCreateForm, accou
|
||||||
emojis = append(emojis, e.ID)
|
emojis = append(emojis, e.ID)
|
||||||
}
|
}
|
||||||
// add full populated gts emojis to the status for passing them around conveniently
|
// 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
|
// add just the ids of the used emojis to the status for putting in the db
|
||||||
status.Emojis = emojis
|
status.EmojiIDs = emojis
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,9 +252,9 @@ func (p *processor) ProcessContent(form *apimodel.AdvancedStatusCreateForm, acco
|
||||||
var formatted string
|
var formatted string
|
||||||
switch form.Format {
|
switch form.Format {
|
||||||
case apimodel.StatusFormatPlain:
|
case apimodel.StatusFormatPlain:
|
||||||
formatted = p.formatter.FromPlain(content, status.GTSMentions, status.GTSTags)
|
formatted = p.formatter.FromPlain(content, status.Mentions, status.Tags)
|
||||||
case apimodel.StatusFormatMarkdown:
|
case apimodel.StatusFormatMarkdown:
|
||||||
formatted = p.formatter.FromMarkdown(content, status.GTSMentions, status.GTSTags)
|
formatted = p.formatter.FromMarkdown(content, status.Mentions, status.Tags)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("format %s not recognised as a valid status format", form.Format)
|
return fmt.Errorf("format %s not recognised as a valid status format", form.Format)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,19 +91,19 @@ func (suite *UtilTestSuite) TestProcessMentions1() {
|
||||||
err := suite.status.ProcessMentions(form, creatingAccount.ID, status)
|
err := suite.status.ProcessMentions(form, creatingAccount.ID, status)
|
||||||
assert.NoError(suite.T(), err)
|
assert.NoError(suite.T(), err)
|
||||||
|
|
||||||
assert.Len(suite.T(), status.GTSMentions, 1)
|
assert.Len(suite.T(), status.Mentions, 1)
|
||||||
newMention := status.GTSMentions[0]
|
newMention := status.Mentions[0]
|
||||||
assert.Equal(suite.T(), mentionedAccount.ID, newMention.TargetAccountID)
|
assert.Equal(suite.T(), mentionedAccount.ID, newMention.TargetAccountID)
|
||||||
assert.Equal(suite.T(), creatingAccount.ID, newMention.OriginAccountID)
|
assert.Equal(suite.T(), creatingAccount.ID, newMention.OriginAccountID)
|
||||||
assert.Equal(suite.T(), creatingAccount.URI, newMention.OriginAccountURI)
|
assert.Equal(suite.T(), creatingAccount.URI, newMention.OriginAccountURI)
|
||||||
assert.Equal(suite.T(), status.ID, newMention.StatusID)
|
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(), fmt.Sprintf("@%s@%s", mentionedAccount.Username, mentionedAccount.Domain), newMention.NameString)
|
||||||
assert.Equal(suite.T(), mentionedAccount.URI, newMention.MentionedAccountURI)
|
assert.Equal(suite.T(), mentionedAccount.URI, newMention.TargetAccountURI)
|
||||||
assert.Equal(suite.T(), mentionedAccount.URL, newMention.MentionedAccountURL)
|
assert.Equal(suite.T(), mentionedAccount.URL, newMention.TargetAccountURL)
|
||||||
assert.NotNil(suite.T(), newMention.GTSAccount)
|
assert.NotNil(suite.T(), newMention.OriginAccount)
|
||||||
|
|
||||||
assert.Len(suite.T(), status.Mentions, 1)
|
assert.Len(suite.T(), status.MentionIDs, 1)
|
||||||
assert.Equal(suite.T(), newMention.ID, status.Mentions[0])
|
assert.Equal(suite.T(), newMention.ID, status.MentionIDs[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *UtilTestSuite) TestProcessContentFull1() {
|
func (suite *UtilTestSuite) TestProcessContentFull1() {
|
||||||
|
|
@ -232,19 +232,19 @@ func (suite *UtilTestSuite) TestProcessMentions2() {
|
||||||
err := suite.status.ProcessMentions(form, creatingAccount.ID, status)
|
err := suite.status.ProcessMentions(form, creatingAccount.ID, status)
|
||||||
assert.NoError(suite.T(), err)
|
assert.NoError(suite.T(), err)
|
||||||
|
|
||||||
assert.Len(suite.T(), status.GTSMentions, 1)
|
assert.Len(suite.T(), status.Mentions, 1)
|
||||||
newMention := status.GTSMentions[0]
|
newMention := status.Mentions[0]
|
||||||
assert.Equal(suite.T(), mentionedAccount.ID, newMention.TargetAccountID)
|
assert.Equal(suite.T(), mentionedAccount.ID, newMention.TargetAccountID)
|
||||||
assert.Equal(suite.T(), creatingAccount.ID, newMention.OriginAccountID)
|
assert.Equal(suite.T(), creatingAccount.ID, newMention.OriginAccountID)
|
||||||
assert.Equal(suite.T(), creatingAccount.URI, newMention.OriginAccountURI)
|
assert.Equal(suite.T(), creatingAccount.URI, newMention.OriginAccountURI)
|
||||||
assert.Equal(suite.T(), status.ID, newMention.StatusID)
|
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(), fmt.Sprintf("@%s@%s", mentionedAccount.Username, mentionedAccount.Domain), newMention.NameString)
|
||||||
assert.Equal(suite.T(), mentionedAccount.URI, newMention.MentionedAccountURI)
|
assert.Equal(suite.T(), mentionedAccount.URI, newMention.TargetAccountURI)
|
||||||
assert.Equal(suite.T(), mentionedAccount.URL, newMention.MentionedAccountURL)
|
assert.Equal(suite.T(), mentionedAccount.URL, newMention.TargetAccountURL)
|
||||||
assert.NotNil(suite.T(), newMention.GTSAccount)
|
assert.NotNil(suite.T(), newMention.OriginAccount)
|
||||||
|
|
||||||
assert.Len(suite.T(), status.Mentions, 1)
|
assert.Len(suite.T(), status.MentionIDs, 1)
|
||||||
assert.Equal(suite.T(), newMention.ID, status.Mentions[0])
|
assert.Equal(suite.T(), newMention.ID, status.MentionIDs[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *UtilTestSuite) TestProcessContentFull2() {
|
func (suite *UtilTestSuite) TestProcessContentFull2() {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
// make sure we have a target account, either by getting one pinned on the mention,
|
||||||
// or by pulling it from the database
|
// or by pulling it from the database
|
||||||
var targetAccount *gtsmodel.Account
|
var targetAccount *gtsmodel.Account
|
||||||
if menchie.GTSAccount != nil {
|
if menchie.OriginAccount != nil {
|
||||||
// got it from the mention
|
// got it from the mention
|
||||||
targetAccount = menchie.GTSAccount
|
targetAccount = menchie.OriginAccount
|
||||||
} else {
|
} else {
|
||||||
a := >smodel.Account{}
|
a := >smodel.Account{}
|
||||||
if err := f.db.GetByID(menchie.TargetAccountID, a); err == nil {
|
if err := f.db.GetByID(menchie.TargetAccountID, a); err == nil {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
// attachments to dereference and fetch later on (we don't do that here)
|
||||||
if attachments, err := ap.ExtractAttachments(statusable); err == nil {
|
if attachments, err := ap.ExtractAttachments(statusable); err == nil {
|
||||||
status.GTSMediaAttachments = attachments
|
status.Attachments = attachments
|
||||||
}
|
}
|
||||||
|
|
||||||
// hashtags to dereference later on
|
// hashtags to dereference later on
|
||||||
if hashtags, err := ap.ExtractHashtags(statusable); err == nil {
|
if hashtags, err := ap.ExtractHashtags(statusable); err == nil {
|
||||||
status.GTSTags = hashtags
|
status.Tags = hashtags
|
||||||
}
|
}
|
||||||
|
|
||||||
// emojis to dereference and fetch later on
|
// emojis to dereference and fetch later on
|
||||||
if emojis, err := ap.ExtractEmojis(statusable); err == nil {
|
if emojis, err := ap.ExtractEmojis(statusable); err == nil {
|
||||||
status.GTSEmojis = emojis
|
status.Emojis = emojis
|
||||||
}
|
}
|
||||||
|
|
||||||
// mentions to dereference later on
|
// mentions to dereference later on
|
||||||
if mentions, err := ap.ExtractMentions(statusable); err == nil {
|
if mentions, err := ap.ExtractMentions(statusable); err == nil {
|
||||||
status.GTSMentions = mentions
|
status.Mentions = mentions
|
||||||
}
|
}
|
||||||
|
|
||||||
// cw string for this status
|
// cw string for this status
|
||||||
|
|
@ -515,10 +515,10 @@ func (c *converter) ASAnnounceToStatus(announceable ap.Announceable) (*gtsmodel.
|
||||||
status.AccountURI = boostingAccount.URI
|
status.AccountURI = boostingAccount.URI
|
||||||
|
|
||||||
// these will all be wrapped in the boosted status so set them empty here
|
// these will all be wrapped in the boosted status so set them empty here
|
||||||
status.Attachments = []string{}
|
status.AttachmentIDs = []string{}
|
||||||
status.Tags = []string{}
|
status.TagIDs = []string{}
|
||||||
status.Mentions = []string{}
|
status.MentionIDs = []string{}
|
||||||
status.Emojis = []string{}
|
status.EmojiIDs = []string{}
|
||||||
|
|
||||||
// parse the visibility from the To and CC entries
|
// parse the visibility from the To and CC entries
|
||||||
var visibility gtsmodel.Visibility
|
var visibility gtsmodel.Visibility
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,10 @@ func (c *converter) StatusToBoost(s *gtsmodel.Status, boostingAccount *gtsmodel.
|
||||||
InReplyToAccountID: "",
|
InReplyToAccountID: "",
|
||||||
|
|
||||||
// these will all be wrapped in the boosted status so set them empty here
|
// these will all be wrapped in the boosted status so set them empty here
|
||||||
Attachments: []string{},
|
AttachmentIDs: []string{},
|
||||||
Tags: []string{},
|
TagIDs: []string{},
|
||||||
Mentions: []string{},
|
MentionIDs: []string{},
|
||||||
Emojis: []string{},
|
EmojiIDs: []string{},
|
||||||
|
|
||||||
// the below fields will be taken from the target status
|
// the below fields will be taken from the target status
|
||||||
Content: s.Content,
|
Content: s.Content,
|
||||||
|
|
|
||||||
|
|
@ -408,7 +408,7 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e
|
||||||
tagProp := streams.NewActivityStreamsTagProperty()
|
tagProp := streams.NewActivityStreamsTagProperty()
|
||||||
|
|
||||||
// tag -- mentions
|
// tag -- mentions
|
||||||
for _, m := range s.GTSMentions {
|
for _, m := range s.Mentions {
|
||||||
asMention, err := c.MentionToAS(m)
|
asMention, err := c.MentionToAS(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("StatusToAS: error converting mention to AS mention: %s", err)
|
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 {
|
switch s.Visibility {
|
||||||
case gtsmodel.VisibilityDirect:
|
case gtsmodel.VisibilityDirect:
|
||||||
// if DIRECT, then only mentioned users should be added to TO, and nothing to CC
|
// if DIRECT, then only mentioned users should be added to TO, and nothing to CC
|
||||||
for _, m := range s.GTSMentions {
|
for _, m := range s.Mentions {
|
||||||
iri, err := url.Parse(m.GTSAccount.URI)
|
iri, err := url.Parse(m.OriginAccount.URI)
|
||||||
if err != nil {
|
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)
|
toProp.AppendIRI(iri)
|
||||||
}
|
}
|
||||||
|
|
@ -453,10 +453,10 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e
|
||||||
case gtsmodel.VisibilityFollowersOnly:
|
case gtsmodel.VisibilityFollowersOnly:
|
||||||
// if FOLLOWERS ONLY then we want to add followers to TO, and mentions to CC
|
// if FOLLOWERS ONLY then we want to add followers to TO, and mentions to CC
|
||||||
toProp.AppendIRI(authorFollowersURI)
|
toProp.AppendIRI(authorFollowersURI)
|
||||||
for _, m := range s.GTSMentions {
|
for _, m := range s.Mentions {
|
||||||
iri, err := url.Parse(m.GTSAccount.URI)
|
iri, err := url.Parse(m.OriginAccount.URI)
|
||||||
if err != nil {
|
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)
|
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
|
// if UNLOCKED, we want to add followers to TO, and public and mentions to CC
|
||||||
toProp.AppendIRI(authorFollowersURI)
|
toProp.AppendIRI(authorFollowersURI)
|
||||||
ccProp.AppendIRI(publicURI)
|
ccProp.AppendIRI(publicURI)
|
||||||
for _, m := range s.GTSMentions {
|
for _, m := range s.Mentions {
|
||||||
iri, err := url.Parse(m.GTSAccount.URI)
|
iri, err := url.Parse(m.OriginAccount.URI)
|
||||||
if err != nil {
|
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)
|
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
|
// if PUBLIC, we want to add public to TO, and followers and mentions to CC
|
||||||
toProp.AppendIRI(publicURI)
|
toProp.AppendIRI(publicURI)
|
||||||
ccProp.AppendIRI(authorFollowersURI)
|
ccProp.AppendIRI(authorFollowersURI)
|
||||||
for _, m := range s.GTSMentions {
|
for _, m := range s.Mentions {
|
||||||
iri, err := url.Parse(m.GTSAccount.URI)
|
iri, err := url.Parse(m.OriginAccount.URI)
|
||||||
if err != nil {
|
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)
|
ccProp.AppendIRI(iri)
|
||||||
}
|
}
|
||||||
|
|
@ -496,7 +496,7 @@ func (c *converter) StatusToAS(s *gtsmodel.Status) (vocab.ActivityStreamsNote, e
|
||||||
|
|
||||||
// attachment
|
// attachment
|
||||||
attachmentProp := streams.NewActivityStreamsAttachmentProperty()
|
attachmentProp := streams.NewActivityStreamsAttachmentProperty()
|
||||||
for _, a := range s.GTSMediaAttachments {
|
for _, a := range s.Attachments {
|
||||||
doc, err := c.AttachmentToAS(a)
|
doc, err := c.AttachmentToAS(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("StatusToAS: error converting attachment: %s", err)
|
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) {
|
func (c *converter) MentionToAS(m *gtsmodel.Mention) (vocab.ActivityStreamsMention, error) {
|
||||||
if m.GTSAccount == nil {
|
if m.OriginAccount == nil {
|
||||||
a := >smodel.Account{}
|
a := >smodel.Account{}
|
||||||
if err := c.db.GetWhere([]db.Where{{Key: "target_account_id", Value: m.TargetAccountID}}, a); err != nil {
|
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)
|
return nil, fmt.Errorf("MentionToAS: error getting target account from db: %s", err)
|
||||||
}
|
}
|
||||||
m.GTSAccount = a
|
m.OriginAccount = a
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the mention
|
// 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
|
// href -- this should be the URI of the mentioned user
|
||||||
hrefProp := streams.NewActivityStreamsHrefProperty()
|
hrefProp := streams.NewActivityStreamsHrefProperty()
|
||||||
hrefURI, err := url.Parse(m.GTSAccount.URI)
|
hrefURI, err := url.Parse(m.OriginAccount.URI)
|
||||||
if err != nil {
|
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)
|
hrefProp.SetIRI(hrefURI)
|
||||||
mention.SetActivityStreamsHref(hrefProp)
|
mention.SetActivityStreamsHref(hrefProp)
|
||||||
|
|
||||||
// name -- this should be the namestring of the mentioned user, something like @whatever@example.org
|
// name -- this should be the namestring of the mentioned user, something like @whatever@example.org
|
||||||
var domain string
|
var domain string
|
||||||
if m.GTSAccount.Domain == "" {
|
if m.OriginAccount.Domain == "" {
|
||||||
domain = c.config.AccountDomain
|
domain = c.config.AccountDomain
|
||||||
} else {
|
} else {
|
||||||
domain = m.GTSAccount.Domain
|
domain = m.OriginAccount.Domain
|
||||||
}
|
}
|
||||||
username := m.GTSAccount.Username
|
username := m.OriginAccount.Username
|
||||||
nameString := fmt.Sprintf("@%s@%s", username, domain)
|
nameString := fmt.Sprintf("@%s@%s", username, domain)
|
||||||
nameProp := streams.NewActivityStreamsNameProperty()
|
nameProp := streams.NewActivityStreamsNameProperty()
|
||||||
nameProp.AppendXMLSchemaString(nameString)
|
nameProp.AppendXMLSchemaString(nameString)
|
||||||
|
|
|
||||||
|
|
@ -357,8 +357,8 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode
|
||||||
mastoAttachments := []model.Attachment{}
|
mastoAttachments := []model.Attachment{}
|
||||||
// the status might already have some gts attachments on it if it's not been pulled directly from the database
|
// 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 so, we can directly convert the gts attachments into masto ones
|
||||||
if s.GTSMediaAttachments != nil {
|
if s.Attachments != nil {
|
||||||
for _, gtsAttachment := range s.GTSMediaAttachments {
|
for _, gtsAttachment := range s.Attachments {
|
||||||
mastoAttachment, err := c.AttachmentToMasto(gtsAttachment)
|
mastoAttachment, err := c.AttachmentToMasto(gtsAttachment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error converting attachment with id %s: %s", gtsAttachment.ID, err)
|
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
|
// 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
|
// in this case, we need to pull the gts attachments from the db to convert them into masto ones
|
||||||
} else {
|
} else {
|
||||||
for _, a := range s.Attachments {
|
for _, a := range s.AttachmentIDs {
|
||||||
gtsAttachment := >smodel.MediaAttachment{}
|
gtsAttachment := >smodel.MediaAttachment{}
|
||||||
if err := c.db.GetByID(a, gtsAttachment); err != nil {
|
if err := c.db.GetByID(a, gtsAttachment); err != nil {
|
||||||
return nil, fmt.Errorf("error getting attachment with id %s: %s", a, err)
|
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{}
|
mastoMentions := []model.Mention{}
|
||||||
// the status might already have some gts mentions on it if it's not been pulled directly from the database
|
// 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 so, we can directly convert the gts mentions into masto ones
|
||||||
if s.GTSMentions != nil {
|
if s.Mentions != nil {
|
||||||
for _, gtsMention := range s.GTSMentions {
|
for _, gtsMention := range s.Mentions {
|
||||||
mastoMention, err := c.MentionToMasto(gtsMention)
|
mastoMention, err := c.MentionToMasto(gtsMention)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error converting mention with id %s: %s", gtsMention.ID, err)
|
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
|
// 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
|
// in this case, we need to pull the gts mentions from the db to convert them into masto ones
|
||||||
} else {
|
} else {
|
||||||
for _, m := range s.Mentions {
|
for _, m := range s.MentionIDs {
|
||||||
gtsMention := >smodel.Mention{}
|
gtsMention := >smodel.Mention{}
|
||||||
if err := c.db.GetByID(m, gtsMention); err != nil {
|
if err := c.db.GetByID(m, gtsMention); err != nil {
|
||||||
return nil, fmt.Errorf("error getting mention with id %s: %s", m, err)
|
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{}
|
mastoTags := []model.Tag{}
|
||||||
// the status might already have some gts tags on it if it's not been pulled directly from the database
|
// 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 so, we can directly convert the gts tags into masto ones
|
||||||
if s.GTSTags != nil {
|
if s.Tags != nil {
|
||||||
for _, gtsTag := range s.GTSTags {
|
for _, gtsTag := range s.Tags {
|
||||||
mastoTag, err := c.TagToMasto(gtsTag)
|
mastoTag, err := c.TagToMasto(gtsTag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error converting tag with id %s: %s", gtsTag.ID, err)
|
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
|
// 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
|
// in this case, we need to pull the gts tags from the db to convert them into masto ones
|
||||||
} else {
|
} else {
|
||||||
for _, t := range s.Tags {
|
for _, t := range s.TagIDs {
|
||||||
gtsTag := >smodel.Tag{}
|
gtsTag := >smodel.Tag{}
|
||||||
if err := c.db.GetByID(t, gtsTag); err != nil {
|
if err := c.db.GetByID(t, gtsTag); err != nil {
|
||||||
return nil, fmt.Errorf("error getting tag with id %s: %s", t, err)
|
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{}
|
mastoEmojis := []model.Emoji{}
|
||||||
// the status might already have some gts emojis on it if it's not been pulled directly from the database
|
// 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 so, we can directly convert the gts emojis into masto ones
|
||||||
if s.GTSEmojis != nil {
|
if s.Emojis != nil {
|
||||||
for _, gtsEmoji := range s.GTSEmojis {
|
for _, gtsEmoji := range s.Emojis {
|
||||||
mastoEmoji, err := c.EmojiToMasto(gtsEmoji)
|
mastoEmoji, err := c.EmojiToMasto(gtsEmoji)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error converting emoji with id %s: %s", gtsEmoji.ID, err)
|
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
|
// 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
|
// in this case, we need to pull the gts emojis from the db to convert them into masto ones
|
||||||
} else {
|
} else {
|
||||||
for _, e := range s.Emojis {
|
for _, e := range s.EmojiIDs {
|
||||||
gtsEmoji := >smodel.Emoji{}
|
gtsEmoji := >smodel.Emoji{}
|
||||||
if err := c.db.GetByID(e, gtsEmoji); err != nil {
|
if err := c.db.GetByID(e, gtsEmoji); err != nil {
|
||||||
return nil, fmt.Errorf("error getting emoji with id %s: %s", e, err)
|
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) {
|
func (c *converter) NotificationToMasto(n *gtsmodel.Notification) (*model.Notification, error) {
|
||||||
|
|
||||||
if n.GTSTargetAccount == nil {
|
if n.TargetAccount == nil {
|
||||||
tAccount := >smodel.Account{}
|
tAccount := >smodel.Account{}
|
||||||
if err := c.db.GetByID(n.TargetAccountID, tAccount); err != nil {
|
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)
|
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 := >smodel.Account{}
|
ogAccount := >smodel.Account{}
|
||||||
if err := c.db.GetByID(n.OriginAccountID, ogAccount); err != nil {
|
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)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NotificationToMasto: error converting account to masto: %s", err)
|
return nil, fmt.Errorf("NotificationToMasto: error converting account to masto: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var mastoStatus *model.Status
|
var mastoStatus *model.Status
|
||||||
if n.StatusID != "" {
|
if n.StatusID != "" {
|
||||||
if n.GTSStatus == nil {
|
if n.Status == nil {
|
||||||
status := >smodel.Status{}
|
status := >smodel.Status{}
|
||||||
if err := c.db.GetByID(n.StatusID, status); err != nil {
|
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)
|
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.Status.Account == nil {
|
||||||
if n.GTSStatus.AccountID == n.GTSTargetAccount.ID {
|
if n.Status.AccountID == n.TargetAccount.ID {
|
||||||
n.GTSStatus.Account = n.GTSTargetAccount
|
n.Status.Account = n.TargetAccount
|
||||||
} else if n.GTSStatus.AccountID == n.GTSOriginAccount.ID {
|
} else if n.Status.AccountID == n.OriginAccount.ID {
|
||||||
n.GTSStatus.Account = n.GTSOriginAccount
|
n.Status.Account = n.OriginAccount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
mastoStatus, err = c.StatusToMasto(n.GTSStatus, nil)
|
mastoStatus, err = c.StatusToMasto(n.Status, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NotificationToMasto: error converting status to masto: %s", err)
|
return nil, fmt.Errorf("NotificationToMasto: error converting status to masto: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
// 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.
|
// 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)
|
l.Debugf("something went wrong figuring out if the accounts have a block: %s", err)
|
||||||
return false, err
|
return false, err
|
||||||
} else if blocked {
|
} else if blocked {
|
||||||
|
|
@ -113,7 +113,7 @@ func (f *filter) StatusVisible(targetStatus *gtsmodel.Status, requestingAccount
|
||||||
|
|
||||||
// status replies to account id
|
// status replies to account id
|
||||||
if relevantAccounts.ReplyToAccount != nil && relevantAccounts.ReplyToAccount.ID != requestingAccount.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
|
return false, err
|
||||||
} else if blocked {
|
} else if blocked {
|
||||||
l.Trace("a block exists between requesting account and reply to account")
|
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
|
// status boosts accounts id
|
||||||
if relevantAccounts.BoostedStatusAuthor != nil {
|
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
|
return false, err
|
||||||
} else if blocked {
|
} else if blocked {
|
||||||
l.Trace("a block exists between requesting account and boosted account")
|
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
|
// status boosts a reply to account id
|
||||||
if relevantAccounts.BoostedReplyToAccount != nil {
|
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
|
return false, err
|
||||||
} else if blocked {
|
} else if blocked {
|
||||||
l.Trace("a block exists between requesting account and boosted reply to account")
|
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
|
// status mentions accounts
|
||||||
for _, a := range relevantAccounts.MentionedAccounts {
|
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
|
return false, err
|
||||||
} else if blocked {
|
} else if blocked {
|
||||||
l.Trace("a block exists between requesting account and a mentioned account")
|
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
|
// boost mentions accounts
|
||||||
for _, a := range relevantAccounts.BoostedMentionedAccounts {
|
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
|
return false, err
|
||||||
} else if blocked {
|
} else if blocked {
|
||||||
l.Trace("a block exists between requesting account and a boosted mentioned account")
|
l.Trace("a block exists between requesting account and a boosted mentioned account")
|
||||||
|
|
|
||||||
|
|
@ -13,28 +13,71 @@ func (f *filter) pullRelevantAccountsFromStatus(targetStatus *gtsmodel.Status) (
|
||||||
BoostedMentionedAccounts: []*gtsmodel.Account{},
|
BoostedMentionedAccounts: []*gtsmodel.Account{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the author account
|
// get the author account if it's not set on the status already
|
||||||
if targetStatus.Account == nil {
|
if targetStatus.Account == nil {
|
||||||
statusAuthor := >smodel.Account{}
|
statusAuthor, err := f.db.GetAccountByID(targetStatus.AccountID)
|
||||||
if err := f.db.GetByID(targetStatus.AccountID, statusAuthor); err != nil {
|
if err != nil {
|
||||||
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting statusAuthor with id %s: %s", targetStatus.AccountID, err)
|
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting statusAuthor with id %s: %s", targetStatus.AccountID, err)
|
||||||
}
|
}
|
||||||
targetStatus.Account = statusAuthor
|
targetStatus.Account = statusAuthor
|
||||||
}
|
}
|
||||||
accounts.StatusAuthor = targetStatus.Account
|
accounts.StatusAuthor = targetStatus.Account
|
||||||
|
|
||||||
// get the replied to account from the status and add it to the pile
|
// get the replied to account if it's not set on the status already
|
||||||
if targetStatus.InReplyToAccountID != "" {
|
if targetStatus.InReplyToAccountID != "" && targetStatus.InReplyToAccount == nil {
|
||||||
repliedToAccount := >smodel.Account{}
|
repliedToAccount, err := f.db.GetAccountByID(targetStatus.InReplyToAccountID)
|
||||||
if err := f.db.GetByID(targetStatus.InReplyToAccountID, repliedToAccount); err != nil {
|
if err != nil {
|
||||||
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting repliedToAcount with id %s: %s", targetStatus.InReplyToAccountID, err)
|
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
|
// now get all accounts with IDs that are mentioned in the status
|
||||||
for _, mentionID := range targetStatus.Mentions {
|
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.MentionIDs {
|
||||||
mention := >smodel.Mention{}
|
mention := >smodel.Mention{}
|
||||||
if err := f.db.GetByID(mentionID, mention); err != nil {
|
if err := f.db.GetByID(mentionID, mention); err != nil {
|
||||||
return accounts, fmt.Errorf("PullRelevantAccountsFromStatus: error getting mention with id %s: %s", mentionID, err)
|
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)
|
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 := >smodel.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 := >smodel.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 := >smodel.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 := >smodel.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 := >smodel.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
|
return accounts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -793,10 +793,10 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
|
||||||
URI: "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
|
URI: "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
|
||||||
URL: "http://localhost:8080/@admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
|
URL: "http://localhost:8080/@admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
|
||||||
Content: "hello world! #welcome ! first post on the instance :rainbow: !",
|
Content: "hello world! #welcome ! first post on the instance :rainbow: !",
|
||||||
Attachments: []string{"01F8MH6NEM8D7527KZAECTCR76"},
|
AttachmentIDs: []string{"01F8MH6NEM8D7527KZAECTCR76"},
|
||||||
Tags: []string{"01F8MHA1A2NF9MJ3WCCQ3K8BSZ"},
|
TagIDs: []string{"01F8MHA1A2NF9MJ3WCCQ3K8BSZ"},
|
||||||
Mentions: []string{},
|
MentionIDs: []string{},
|
||||||
Emojis: []string{"01F8MH9H8E4VG3KDYJR9EGPXCQ"},
|
EmojiIDs: []string{"01F8MH9H8E4VG3KDYJR9EGPXCQ"},
|
||||||
CreatedAt: time.Now().Add(-71 * time.Hour),
|
CreatedAt: time.Now().Add(-71 * time.Hour),
|
||||||
UpdatedAt: time.Now().Add(-71 * time.Hour),
|
UpdatedAt: time.Now().Add(-71 * time.Hour),
|
||||||
Local: true,
|
Local: true,
|
||||||
|
|
@ -917,7 +917,7 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
|
||||||
URI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MH82FYRXD2RC6108DAJ5HB",
|
URI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MH82FYRXD2RC6108DAJ5HB",
|
||||||
URL: "http://localhost:8080/@the_mighty_zork/statuses/01F8MH82FYRXD2RC6108DAJ5HB",
|
URL: "http://localhost:8080/@the_mighty_zork/statuses/01F8MH82FYRXD2RC6108DAJ5HB",
|
||||||
Content: "here's a little gif of trent",
|
Content: "here's a little gif of trent",
|
||||||
Attachments: []string{"01F8MH7TDVANYKWVE8VVKFPJTJ"},
|
AttachmentIDs: []string{"01F8MH7TDVANYKWVE8VVKFPJTJ"},
|
||||||
CreatedAt: time.Now().Add(-1 * time.Hour),
|
CreatedAt: time.Now().Add(-1 * time.Hour),
|
||||||
UpdatedAt: time.Now().Add(-1 * time.Hour),
|
UpdatedAt: time.Now().Add(-1 * time.Hour),
|
||||||
Local: true,
|
Local: true,
|
||||||
|
|
@ -942,7 +942,7 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
|
||||||
URI: "http://localhost:8080/users/the_mighty_zork/statuses/01FCTA44PW9H1TB328S9AQXKDS",
|
URI: "http://localhost:8080/users/the_mighty_zork/statuses/01FCTA44PW9H1TB328S9AQXKDS",
|
||||||
URL: "http://localhost:8080/@the_mighty_zork/statuses/01FCTA44PW9H1TB328S9AQXKDS",
|
URL: "http://localhost:8080/@the_mighty_zork/statuses/01FCTA44PW9H1TB328S9AQXKDS",
|
||||||
Content: "hi!",
|
Content: "hi!",
|
||||||
Attachments: []string{},
|
AttachmentIDs: []string{},
|
||||||
CreatedAt: time.Now().Add(-1 * time.Minute),
|
CreatedAt: time.Now().Add(-1 * time.Minute),
|
||||||
UpdatedAt: time.Now().Add(-1 * time.Minute),
|
UpdatedAt: time.Now().Add(-1 * time.Minute),
|
||||||
Local: true,
|
Local: true,
|
||||||
|
|
@ -1127,8 +1127,8 @@ func NewTestMentions() map[string]*gtsmodel.Mention {
|
||||||
OriginAccountURI: "http://localhost:8080/users/the_mighty_zork",
|
OriginAccountURI: "http://localhost:8080/users/the_mighty_zork",
|
||||||
TargetAccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX",
|
TargetAccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX",
|
||||||
NameString: "@foss_satan@fossbros-anonymous.io",
|
NameString: "@foss_satan@fossbros-anonymous.io",
|
||||||
MentionedAccountURI: "http://fossbros-anonymous.io/users/foss_satan",
|
TargetAccountURI: "http://fossbros-anonymous.io/users/foss_satan",
|
||||||
MentionedAccountURL: "http://fossbros-anonymous.io/@foss_satan",
|
TargetAccountURL: "http://fossbros-anonymous.io/@foss_satan",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue