too many changes to name honestly

This commit is contained in:
tsmethurst
2021-04-08 23:29:35 +02:00
parent e6c590c065
commit f210d39891
85 changed files with 1178 additions and 587 deletions

View File

@ -28,7 +28,9 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/apimodule"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/mastotypes"
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/router"
@ -43,21 +45,23 @@ const (
)
type accountModule struct {
config *config.Config
db db.DB
oauthServer oauth.Server
mediaHandler media.MediaHandler
log *logrus.Logger
config *config.Config
db db.DB
oauthServer oauth.Server
mediaHandler media.MediaHandler
mastoConverter mastotypes.Converter
log *logrus.Logger
}
// New returns a new account module
func New(config *config.Config, db db.DB, oauthServer oauth.Server, mediaHandler media.MediaHandler, log *logrus.Logger) apimodule.ClientAPIModule {
func New(config *config.Config, db db.DB, oauthServer oauth.Server, mediaHandler media.MediaHandler, mastoConverter mastotypes.Converter, log *logrus.Logger) apimodule.ClientAPIModule {
return &accountModule{
config: config,
db: db,
oauthServer: oauthServer,
mediaHandler: mediaHandler,
log: log,
config: config,
db: db,
oauthServer: oauthServer,
mediaHandler: mediaHandler,
mastoConverter: mastoConverter,
log: log,
}
}
@ -70,14 +74,14 @@ func (m *accountModule) Route(r router.Router) error {
func (m *accountModule) CreateTables(db db.DB) error {
models := []interface{}{
&model.User{},
&model.Account{},
&model.Follow{},
&model.FollowRequest{},
&model.Status{},
&model.Application{},
&model.EmailDomainBlock{},
&model.MediaAttachment{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Follow{},
&gtsmodel.FollowRequest{},
&gtsmodel.Status{},
&gtsmodel.Application{},
&gtsmodel.EmailDomainBlock{},
&gtsmodel.MediaAttachment{},
}
for _, m := range models {

View File

@ -27,10 +27,10 @@ import (
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
mastotypes "github.com/superseriousbusiness/gotosocial/internal/mastotypes/mastomodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/util"
"github.com/superseriousbusiness/gotosocial/pkg/mastotypes"
"github.com/superseriousbusiness/oauth2/v4"
)
@ -83,7 +83,7 @@ func (m *accountModule) accountCreatePOSTHandler(c *gin.Context) {
// accountCreate does the dirty work of making an account and user in the database.
// It then returns a token to the caller, for use with the new account, as per the
// spec here: https://docs.joinmastodon.org/methods/accounts/
func (m *accountModule) accountCreate(form *mastotypes.AccountCreateRequest, signUpIP net.IP, token oauth2.TokenInfo, app *model.Application) (*mastotypes.Token, error) {
func (m *accountModule) accountCreate(form *mastotypes.AccountCreateRequest, signUpIP net.IP, token oauth2.TokenInfo, app *gtsmodel.Application) (*mastotypes.Token, error) {
l := m.log.WithField("func", "accountCreate")
// don't store a reason if we don't require one

View File

@ -41,11 +41,13 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/mastotypes"
mastomodel "github.com/superseriousbusiness/gotosocial/internal/mastotypes/mastomodel"
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/storage"
"github.com/superseriousbusiness/gotosocial/pkg/mastotypes"
"github.com/superseriousbusiness/oauth2/v4"
"github.com/superseriousbusiness/oauth2/v4/models"
oauthmodels "github.com/superseriousbusiness/oauth2/v4/models"
@ -56,12 +58,13 @@ type AccountCreateTestSuite struct {
suite.Suite
config *config.Config
log *logrus.Logger
testAccountLocal *model.Account
testApplication *model.Application
testAccountLocal *gtsmodel.Account
testApplication *gtsmodel.Application
testToken oauth2.TokenInfo
mockOauthServer *oauth.MockServer
mockStorage *storage.MockStorage
mediaHandler media.MediaHandler
mastoConverter mastotypes.Converter
db db.DB
accountModule *accountModule
newUserFormHappyPath url.Values
@ -78,13 +81,13 @@ func (suite *AccountCreateTestSuite) SetupSuite() {
log.SetLevel(logrus.TraceLevel)
suite.log = log
suite.testAccountLocal = &model.Account{
suite.testAccountLocal = &gtsmodel.Account{
ID: uuid.NewString(),
Username: "test_user",
}
// can use this test application throughout
suite.testApplication = &model.Application{
suite.testApplication = &gtsmodel.Application{
ID: "weeweeeeeeeeeeeeee",
Name: "a test application",
Website: "https://some-application-website.com",
@ -158,8 +161,10 @@ func (suite *AccountCreateTestSuite) SetupSuite() {
// set a media handler because some handlers (eg update credentials) need to upload media (new header/avatar)
suite.mediaHandler = media.New(suite.config, suite.db, suite.mockStorage, log)
suite.mastoConverter = mastotypes.New(suite.config, suite.db)
// and finally here's the thing we're actually testing!
suite.accountModule = New(suite.config, suite.db, suite.mockOauthServer, suite.mediaHandler, suite.log).(*accountModule)
suite.accountModule = New(suite.config, suite.db, suite.mockOauthServer, suite.mediaHandler, suite.mastoConverter, suite.log).(*accountModule)
}
func (suite *AccountCreateTestSuite) TearDownSuite() {
@ -172,14 +177,14 @@ func (suite *AccountCreateTestSuite) TearDownSuite() {
func (suite *AccountCreateTestSuite) SetupTest() {
// create all the tables we might need in thie suite
models := []interface{}{
&model.User{},
&model.Account{},
&model.Follow{},
&model.FollowRequest{},
&model.Status{},
&model.Application{},
&model.EmailDomainBlock{},
&model.MediaAttachment{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Follow{},
&gtsmodel.FollowRequest{},
&gtsmodel.Status{},
&gtsmodel.Application{},
&gtsmodel.EmailDomainBlock{},
&gtsmodel.MediaAttachment{},
}
for _, m := range models {
if err := suite.db.CreateTable(m); err != nil {
@ -210,14 +215,14 @@ func (suite *AccountCreateTestSuite) TearDownTest() {
// remove all the tables we might have used so it's clear for the next test
models := []interface{}{
&model.User{},
&model.Account{},
&model.Follow{},
&model.FollowRequest{},
&model.Status{},
&model.Application{},
&model.EmailDomainBlock{},
&model.MediaAttachment{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Follow{},
&gtsmodel.FollowRequest{},
&gtsmodel.Status{},
&gtsmodel.Application{},
&gtsmodel.EmailDomainBlock{},
&gtsmodel.MediaAttachment{},
}
for _, m := range models {
if err := suite.db.DropTable(m); err != nil {
@ -259,7 +264,7 @@ func (suite *AccountCreateTestSuite) TestAccountCreatePOSTHandlerSuccessful() {
defer result.Body.Close()
b, err := ioutil.ReadAll(result.Body)
assert.NoError(suite.T(), err)
t := &mastotypes.Token{}
t := &mastomodel.Token{}
err = json.Unmarshal(b, t)
assert.NoError(suite.T(), err)
assert.Equal(suite.T(), "we're authorized now!", t.AccessToken)
@ -267,7 +272,7 @@ func (suite *AccountCreateTestSuite) TestAccountCreatePOSTHandlerSuccessful() {
// check new account
// 1. we should be able to get the new account from the db
acct := &model.Account{}
acct := &gtsmodel.Account{}
err = suite.db.GetWhere("username", "test_user", acct)
assert.NoError(suite.T(), err)
assert.NotNil(suite.T(), acct)
@ -288,7 +293,7 @@ func (suite *AccountCreateTestSuite) TestAccountCreatePOSTHandlerSuccessful() {
// check new user
// 1. we should be able to get the new user from the db
usr := &model.User{}
usr := &gtsmodel.User{}
err = suite.db.GetWhere("unconfirmed_email", suite.newUserFormHappyPath.Get("email"), usr)
assert.Nil(suite.T(), err)
assert.NotNil(suite.T(), usr)

View File

@ -23,7 +23,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
)
// accountGetHandler serves the account information held by the server in response to a GET
@ -37,7 +37,7 @@ func (m *accountModule) accountGETHandler(c *gin.Context) {
return
}
targetAccount := &model.Account{}
targetAccount := &gtsmodel.Account{}
if err := m.db.GetByID(targetAcctID, targetAccount); err != nil {
if _, ok := err.(db.ErrNoEntries); ok {
c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"})
@ -47,7 +47,7 @@ func (m *accountModule) accountGETHandler(c *gin.Context) {
return
}
acctInfo, err := m.db.AccountToMastoPublic(targetAccount)
acctInfo, err := m.mastoConverter.AccountToMastoPublic(targetAccount)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return

View File

@ -27,10 +27,10 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
mastotypes "github.com/superseriousbusiness/gotosocial/internal/mastotypes/mastomodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/util"
"github.com/superseriousbusiness/gotosocial/pkg/mastotypes"
)
// accountUpdateCredentialsPATCHHandler allows a user to modify their account/profile settings.
@ -67,7 +67,7 @@ func (m *accountModule) accountUpdateCredentialsPATCHHandler(c *gin.Context) {
}
if form.Discoverable != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "discoverable", *form.Discoverable, &model.Account{}); err != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "discoverable", *form.Discoverable, &gtsmodel.Account{}); err != nil {
l.Debugf("error updating discoverable: %s", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
@ -75,7 +75,7 @@ func (m *accountModule) accountUpdateCredentialsPATCHHandler(c *gin.Context) {
}
if form.Bot != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "bot", *form.Bot, &model.Account{}); err != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "bot", *form.Bot, &gtsmodel.Account{}); err != nil {
l.Debugf("error updating bot: %s", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
@ -87,7 +87,7 @@ func (m *accountModule) accountUpdateCredentialsPATCHHandler(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := m.db.UpdateOneByID(authed.Account.ID, "display_name", *form.DisplayName, &model.Account{}); err != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "display_name", *form.DisplayName, &gtsmodel.Account{}); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
@ -98,7 +98,7 @@ func (m *accountModule) accountUpdateCredentialsPATCHHandler(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := m.db.UpdateOneByID(authed.Account.ID, "note", *form.Note, &model.Account{}); err != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "note", *form.Note, &gtsmodel.Account{}); err != nil {
l.Debugf("error updating note: %s", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
@ -126,7 +126,7 @@ func (m *accountModule) accountUpdateCredentialsPATCHHandler(c *gin.Context) {
}
if form.Locked != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "locked", *form.Locked, &model.Account{}); err != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "locked", *form.Locked, &gtsmodel.Account{}); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
@ -138,14 +138,14 @@ func (m *accountModule) accountUpdateCredentialsPATCHHandler(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := m.db.UpdateOneByID(authed.Account.ID, "language", *form.Source.Language, &model.Account{}); err != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "language", *form.Source.Language, &gtsmodel.Account{}); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
}
if form.Source.Sensitive != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "locked", *form.Locked, &model.Account{}); err != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "locked", *form.Locked, &gtsmodel.Account{}); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
@ -156,7 +156,7 @@ func (m *accountModule) accountUpdateCredentialsPATCHHandler(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := m.db.UpdateOneByID(authed.Account.ID, "privacy", *form.Source.Privacy, &model.Account{}); err != nil {
if err := m.db.UpdateOneByID(authed.Account.ID, "privacy", *form.Source.Privacy, &gtsmodel.Account{}); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
@ -168,14 +168,14 @@ func (m *accountModule) accountUpdateCredentialsPATCHHandler(c *gin.Context) {
// }
// fetch the account with all updated values set
updatedAccount := &model.Account{}
updatedAccount := &gtsmodel.Account{}
if err := m.db.GetByID(authed.Account.ID, updatedAccount); err != nil {
l.Debugf("could not fetch updated account %s: %s", authed.Account.ID, err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
acctSensitive, err := m.db.AccountToMastoSensitive(updatedAccount)
acctSensitive, err := m.mastoConverter.AccountToMastoSensitive(updatedAccount)
if err != nil {
l.Tracef("could not convert account into mastosensitive account: %s", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
@ -195,7 +195,7 @@ func (m *accountModule) accountUpdateCredentialsPATCHHandler(c *gin.Context) {
// UpdateAccountAvatar does the dirty work of checking the avatar part of an account update form,
// parsing and checking the image, and doing the necessary updates in the database for this to become
// the account's new avatar image.
func (m *accountModule) UpdateAccountAvatar(avatar *multipart.FileHeader, accountID string) (*model.MediaAttachment, error) {
func (m *accountModule) UpdateAccountAvatar(avatar *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) {
var err error
if int(avatar.Size) > m.config.MediaConfig.MaxImageSize {
err = fmt.Errorf("avatar with size %d exceeded max image size of %d bytes", avatar.Size, m.config.MediaConfig.MaxImageSize)
@ -228,7 +228,7 @@ func (m *accountModule) UpdateAccountAvatar(avatar *multipart.FileHeader, accoun
// UpdateAccountHeader does the dirty work of checking the header part of an account update form,
// parsing and checking the image, and doing the necessary updates in the database for this to become
// the account's new header image.
func (m *accountModule) UpdateAccountHeader(header *multipart.FileHeader, accountID string) (*model.MediaAttachment, error) {
func (m *accountModule) UpdateAccountHeader(header *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) {
var err error
if int(header.Size) > m.config.MediaConfig.MaxImageSize {
err = fmt.Errorf("header with size %d exceeded max image size of %d bytes", header.Size, m.config.MediaConfig.MaxImageSize)

View File

@ -39,7 +39,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/mastotypes"
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/storage"
@ -52,12 +53,13 @@ type AccountUpdateTestSuite struct {
suite.Suite
config *config.Config
log *logrus.Logger
testAccountLocal *model.Account
testApplication *model.Application
testAccountLocal *gtsmodel.Account
testApplication *gtsmodel.Application
testToken oauth2.TokenInfo
mockOauthServer *oauth.MockServer
mockStorage *storage.MockStorage
mediaHandler media.MediaHandler
mastoConverter mastotypes.Converter
db db.DB
accountModule *accountModule
newUserFormHappyPath url.Values
@ -74,13 +76,13 @@ func (suite *AccountUpdateTestSuite) SetupSuite() {
log.SetLevel(logrus.TraceLevel)
suite.log = log
suite.testAccountLocal = &model.Account{
suite.testAccountLocal = &gtsmodel.Account{
ID: uuid.NewString(),
Username: "test_user",
}
// can use this test application throughout
suite.testApplication = &model.Application{
suite.testApplication = &gtsmodel.Application{
ID: "weeweeeeeeeeeeeeee",
Name: "a test application",
Website: "https://some-application-website.com",
@ -154,8 +156,10 @@ func (suite *AccountUpdateTestSuite) SetupSuite() {
// set a media handler because some handlers (eg update credentials) need to upload media (new header/avatar)
suite.mediaHandler = media.New(suite.config, suite.db, suite.mockStorage, log)
suite.mastoConverter = mastotypes.New(suite.config, suite.db)
// and finally here's the thing we're actually testing!
suite.accountModule = New(suite.config, suite.db, suite.mockOauthServer, suite.mediaHandler, suite.log).(*accountModule)
suite.accountModule = New(suite.config, suite.db, suite.mockOauthServer, suite.mediaHandler, suite.mastoConverter, suite.log).(*accountModule)
}
func (suite *AccountUpdateTestSuite) TearDownSuite() {
@ -168,14 +172,14 @@ func (suite *AccountUpdateTestSuite) TearDownSuite() {
func (suite *AccountUpdateTestSuite) SetupTest() {
// create all the tables we might need in thie suite
models := []interface{}{
&model.User{},
&model.Account{},
&model.Follow{},
&model.FollowRequest{},
&model.Status{},
&model.Application{},
&model.EmailDomainBlock{},
&model.MediaAttachment{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Follow{},
&gtsmodel.FollowRequest{},
&gtsmodel.Status{},
&gtsmodel.Application{},
&gtsmodel.EmailDomainBlock{},
&gtsmodel.MediaAttachment{},
}
for _, m := range models {
if err := suite.db.CreateTable(m); err != nil {
@ -206,14 +210,14 @@ func (suite *AccountUpdateTestSuite) TearDownTest() {
// remove all the tables we might have used so it's clear for the next test
models := []interface{}{
&model.User{},
&model.Account{},
&model.Follow{},
&model.FollowRequest{},
&model.Status{},
&model.Application{},
&model.EmailDomainBlock{},
&model.MediaAttachment{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Follow{},
&gtsmodel.FollowRequest{},
&gtsmodel.Status{},
&gtsmodel.Application{},
&gtsmodel.EmailDomainBlock{},
&gtsmodel.MediaAttachment{},
}
for _, m := range models {
if err := suite.db.DropTable(m); err != nil {

View File

@ -38,7 +38,7 @@ func (m *accountModule) accountVerifyGETHandler(c *gin.Context) {
}
l.Tracef("retrieved account %+v, converting to mastosensitive...", authed.Account.ID)
acctSensitive, err := m.db.AccountToMastoSensitive(authed.Account)
acctSensitive, err := m.mastoConverter.AccountToMastoSensitive(authed.Account)
if err != nil {
l.Tracef("could not convert account into mastosensitive account: %s", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})

View File

@ -25,7 +25,8 @@ import (
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/apimodule"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/mastotypes"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
@ -33,17 +34,19 @@ import (
const appsPath = "/api/v1/apps"
type appModule struct {
server oauth.Server
db db.DB
log *logrus.Logger
server oauth.Server
db db.DB
mastoConverter mastotypes.Converter
log *logrus.Logger
}
// New returns a new auth module
func New(srv oauth.Server, db db.DB, log *logrus.Logger) apimodule.ClientAPIModule {
func New(srv oauth.Server, db db.DB, mastoConverter mastotypes.Converter, log *logrus.Logger) apimodule.ClientAPIModule {
return &appModule{
server: srv,
db: db,
log: log,
server: srv,
db: db,
mastoConverter: mastoConverter,
log: log,
}
}
@ -57,9 +60,9 @@ func (m *appModule) CreateTables(db db.DB) error {
models := []interface{}{
&oauth.Client{},
&oauth.Token{},
&model.User{},
&model.Account{},
&model.Application{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Application{},
}
for _, m := range models {

View File

@ -24,9 +24,9 @@ import (
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
mastotypes "github.com/superseriousbusiness/gotosocial/internal/mastotypes/mastomodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/pkg/mastotypes"
)
// appsPOSTHandler should be served at https://example.org/api/v1/apps
@ -78,7 +78,7 @@ func (m *appModule) appsPOSTHandler(c *gin.Context) {
vapidKey := uuid.NewString()
// generate the application to put in the database
app := &model.Application{
app := &gtsmodel.Application{
Name: form.ClientName,
Website: form.Website,
RedirectURI: form.RedirectURIs,
@ -108,6 +108,12 @@ func (m *appModule) appsPOSTHandler(c *gin.Context) {
return
}
mastoApp, err := m.mastoConverter.AppToMastoSensitive(app)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// done, return the new app information per the spec here: https://docs.joinmastodon.org/methods/apps/
c.JSON(http.StatusOK, app.ToMastoSensitive())
c.JSON(http.StatusOK, mastoApp)
}

View File

@ -31,7 +31,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/apimodule"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
@ -75,9 +75,9 @@ func (m *authModule) CreateTables(db db.DB) error {
models := []interface{}{
&oauth.Client{},
&oauth.Token{},
&model.User{},
&model.Account{},
&model.Application{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Application{},
}
for _, m := range models {

View File

@ -29,7 +29,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/router"
"golang.org/x/crypto/bcrypt"
@ -39,9 +39,9 @@ type AuthTestSuite struct {
suite.Suite
oauthServer oauth.Server
db db.DB
testAccount *model.Account
testApplication *model.Application
testUser *model.User
testAccount *gtsmodel.Account
testApplication *gtsmodel.Application
testUser *gtsmodel.User
testClient *oauth.Client
config *config.Config
}
@ -75,11 +75,11 @@ func (suite *AuthTestSuite) SetupSuite() {
acctID := uuid.NewString()
suite.testAccount = &model.Account{
suite.testAccount = &gtsmodel.Account{
ID: acctID,
Username: "test_user",
}
suite.testUser = &model.User{
suite.testUser = &gtsmodel.User{
EncryptedPassword: string(encryptedPassword),
Email: "user@example.org",
AccountID: acctID,
@ -89,7 +89,7 @@ func (suite *AuthTestSuite) SetupSuite() {
Secret: "some-secret",
Domain: fmt.Sprintf("%s://%s", c.Protocol, c.Host),
}
suite.testApplication = &model.Application{
suite.testApplication = &gtsmodel.Application{
Name: "a test application",
Website: "https://some-application-website.com",
RedirectURI: "http://localhost:8080",
@ -115,9 +115,9 @@ func (suite *AuthTestSuite) SetupTest() {
models := []interface{}{
&oauth.Client{},
&oauth.Token{},
&model.User{},
&model.Account{},
&model.Application{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Application{},
}
for _, m := range models {
@ -148,9 +148,9 @@ func (suite *AuthTestSuite) TearDownTest() {
models := []interface{}{
&oauth.Client{},
&oauth.Token{},
&model.User{},
&model.Account{},
&model.Application{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Application{},
}
for _, m := range models {
if err := suite.db.DropTable(m); err != nil {

View File

@ -27,8 +27,8 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/pkg/mastotypes"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/mastotypes/mastomodel"
)
// authorizeGETHandler should be served as GET at https://example.org/oauth/authorize
@ -57,7 +57,7 @@ func (m *authModule) authorizeGETHandler(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": "no client_id found in session"})
return
}
app := &model.Application{
app := &gtsmodel.Application{
ClientID: clientID,
}
if err := m.db.GetWhere("client_id", app.ClientID, app); err != nil {
@ -66,7 +66,7 @@ func (m *authModule) authorizeGETHandler(c *gin.Context) {
}
// we can also use the userid of the user to fetch their username from the db to greet them nicely <3
user := &model.User{
user := &gtsmodel.User{
ID: userID,
}
if err := m.db.GetByID(user.ID, user); err != nil {
@ -74,7 +74,7 @@ func (m *authModule) authorizeGETHandler(c *gin.Context) {
return
}
acct := &model.Account{
acct := &gtsmodel.Account{
ID: user.AccountID,
}

View File

@ -20,7 +20,7 @@ package auth
import (
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@ -46,7 +46,7 @@ func (m *authModule) oauthTokenMiddleware(c *gin.Context) {
l.Tracef("authenticated user %s with bearer token, scope is %s", uid, ti.GetScope())
// fetch user's and account for this user id
user := &model.User{}
user := &gtsmodel.User{}
if err := m.db.GetByID(uid, user); err != nil || user == nil {
l.Warnf("no user found for validated uid %s", uid)
return
@ -54,7 +54,7 @@ func (m *authModule) oauthTokenMiddleware(c *gin.Context) {
c.Set(oauth.SessionAuthorizedUser, user)
l.Tracef("set gin context %s to %+v", oauth.SessionAuthorizedUser, user)
acct := &model.Account{}
acct := &gtsmodel.Account{}
if err := m.db.GetByID(user.AccountID, acct); err != nil || acct == nil {
l.Warnf("no account found for validated user %s", uid)
return
@ -66,7 +66,7 @@ func (m *authModule) oauthTokenMiddleware(c *gin.Context) {
// check for application token
if cid := ti.GetClientID(); cid != "" {
l.Tracef("authenticated client %s with bearer token, scope is %s", cid, ti.GetScope())
app := &model.Application{}
app := &gtsmodel.Application{}
if err := m.db.GetWhere("client_id", cid, app); err != nil {
l.Tracef("no app found for client %s", cid)
}

View File

@ -24,7 +24,7 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"golang.org/x/crypto/bcrypt"
)
@ -84,7 +84,7 @@ func (m *authModule) validatePassword(email string, password string) (userid str
}
// first we select the user from the database based on email address, bail if no user found for that email
gtsUser := &model.User{}
gtsUser := &gtsmodel.User{}
if err := m.db.GetWhere("email", email, gtsUser); err != nil {
l.Debugf("user %s was not retrievable from db during oauth authorization attempt: %s", email, err)

View File

@ -7,7 +7,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/apimodule"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/router"
"github.com/superseriousbusiness/gotosocial/internal/storage"
)
@ -44,14 +44,14 @@ func (m *fileServer) Route(s router.Router) error {
func (m *fileServer) CreateTables(db db.DB) error {
models := []interface{}{
&model.User{},
&model.Account{},
&model.Follow{},
&model.FollowRequest{},
&model.Status{},
&model.Application{},
&model.EmailDomainBlock{},
&model.MediaAttachment{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Follow{},
&gtsmodel.FollowRequest{},
&gtsmodel.Status{},
&gtsmodel.Application{},
&gtsmodel.EmailDomainBlock{},
&gtsmodel.MediaAttachment{},
}
for _, m := range models {

View File

@ -25,8 +25,9 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/apimodule"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/distributor"
"github.com/superseriousbusiness/gotosocial/internal/mastotypes"
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/router"
@ -51,22 +52,24 @@ const (
)
type statusModule struct {
config *config.Config
db db.DB
oauthServer oauth.Server
mediaHandler media.MediaHandler
distributor distributor.Distributor
log *logrus.Logger
config *config.Config
db db.DB
oauthServer oauth.Server
mediaHandler media.MediaHandler
mastoConverter mastotypes.Converter
distributor distributor.Distributor
log *logrus.Logger
}
// New returns a new account module
func New(config *config.Config, db db.DB, oauthServer oauth.Server, mediaHandler media.MediaHandler, distributor distributor.Distributor, log *logrus.Logger) apimodule.ClientAPIModule {
func New(config *config.Config, db db.DB, oauthServer oauth.Server, mediaHandler media.MediaHandler, mastoConverter mastotypes.Converter, distributor distributor.Distributor, log *logrus.Logger) apimodule.ClientAPIModule {
return &statusModule{
config: config,
db: db,
mediaHandler: mediaHandler,
distributor: distributor,
log: log,
config: config,
db: db,
mediaHandler: mediaHandler,
mastoConverter: mastoConverter,
distributor: distributor,
log: log,
}
}
@ -79,17 +82,17 @@ func (m *statusModule) Route(r router.Router) error {
func (m *statusModule) CreateTables(db db.DB) error {
models := []interface{}{
&model.User{},
&model.Account{},
&model.Follow{},
&model.FollowRequest{},
&model.Status{},
&model.Application{},
&model.EmailDomainBlock{},
&model.MediaAttachment{},
&model.Emoji{},
&model.Tag{},
&model.Mention{},
&gtsmodel.User{},
&gtsmodel.Account{},
&gtsmodel.Follow{},
&gtsmodel.FollowRequest{},
&gtsmodel.Status{},
&gtsmodel.Application{},
&gtsmodel.EmailDomainBlock{},
&gtsmodel.MediaAttachment{},
&gtsmodel.Emoji{},
&gtsmodel.Tag{},
&gtsmodel.Mention{},
}
for _, m := range models {

View File

@ -28,11 +28,11 @@ import (
"github.com/google/uuid"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/distributor"
mastotypes "github.com/superseriousbusiness/gotosocial/internal/mastotypes/mastomodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/util"
"github.com/superseriousbusiness/gotosocial/pkg/mastotypes"
)
type advancedStatusCreateForm struct {
@ -42,7 +42,7 @@ type advancedStatusCreateForm struct {
type advancedVisibilityFlagsForm struct {
// The gotosocial visibility model
VisibilityAdvanced *model.Visibility `form:"visibility_advanced"`
VisibilityAdvanced *gtsmodel.Visibility `form:"visibility_advanced"`
// This status will be federated beyond the local timeline(s)
Federated *bool `form:"federated"`
// This status can be boosted/reblogged
@ -96,7 +96,7 @@ func (m *statusModule) statusCreatePOSTHandler(c *gin.Context) {
thisStatusID := uuid.NewString()
thisStatusURI := fmt.Sprintf("%s/%s", uris.StatusesURI, thisStatusID)
thisStatusURL := fmt.Sprintf("%s/%s", uris.StatusesURL, thisStatusID)
newStatus := &model.Status{
newStatus := &gtsmodel.Status{
ID: thisStatusID,
URI: thisStatusURI,
URL: thisStatusURL,
@ -106,7 +106,7 @@ func (m *statusModule) statusCreatePOSTHandler(c *gin.Context) {
Local: true,
AccountID: authed.Account.ID,
ContentWarning: form.SpoilerText,
ActivityStreamsType: model.ActivityStreamsNote,
ActivityStreamsType: gtsmodel.ActivityStreamsNote,
Sensitive: form.Sensitive,
Language: form.Language,
}
@ -135,16 +135,23 @@ func (m *statusModule) statusCreatePOSTHandler(c *gin.Context) {
return
}
// convert mentions to *model.Mention
// convert mentions to *gtsmodel.Mention
menchies, err := m.db.MentionStringsToMentions(util.DeriveMentions(form.Status), authed.Account.ID, thisStatusID)
if err != nil {
l.Debugf("error generating mentions from status: %s", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "error generating mentions from status"})
return
}
for _, menchie := range menchies {
if err := m.db.Put(menchie); err != nil {
l.Debugf("error putting mentions in db: %s", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "db error while generating mentions from status"})
return
}
}
newStatus.Mentions = menchies
// convert tags to *model.Tag
// convert tags to *gtsmodel.Tag
tags, err := m.db.TagStringsToTags(util.DeriveHashtags(form.Status), authed.Account.ID, thisStatusID)
if err != nil {
l.Debugf("error generating hashtags from status: %s", err)
@ -153,7 +160,7 @@ func (m *statusModule) statusCreatePOSTHandler(c *gin.Context) {
}
newStatus.Tags = tags
// convert emojis to *model.Emoji
// convert emojis to *gtsmodel.Emoji
emojis, err := m.db.EmojiStringsToEmojis(util.DeriveEmojis(form.Status), authed.Account.ID, thisStatusID)
if err != nil {
l.Debugf("error generating emojis from status: %s", err)
@ -170,33 +177,64 @@ func (m *statusModule) statusCreatePOSTHandler(c *gin.Context) {
// pass to the distributor to take care of side effects -- federation, mentions, updating metadata, etc, etc
m.distributor.FromClientAPI() <- distributor.FromClientAPI{
APObjectType: model.ActivityStreamsNote,
APActivityType: model.ActivityStreamsCreate,
APObjectType: gtsmodel.ActivityStreamsNote,
APActivityType: gtsmodel.ActivityStreamsCreate,
Activity: newStatus,
}
// return populated status to submitter
mastoAccount, err := m.db.AccountToMastoPublic(authed.Account)
// now we need to build up the mastodon-style status object to return to the submitter
mastoVis := util.ParseMastoVisFromGTSVis(newStatus.Visibility)
mastoAccount, err := m.mastoConverter.AccountToMastoPublic(authed.Account)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
mastoAttachments := []mastotypes.Attachment{}
for _, a := range newStatus.Attachments {
ma, err := m.mastoConverter.AttachmentToMasto(a)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
mastoAttachments = append(mastoAttachments, ma)
}
mastoMentions := []mastotypes.Mention{}
for _, gtsm := range newStatus.Mentions {
mm, err := m.mastoConverter.MentionToMasto(gtsm)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
mastoMentions = append(mastoMentions, mm)
}
mastoApplication, err := m.mastoConverter.AppToMastoPublic(authed.Application)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
mastoStatus := &mastotypes.Status{
ID: newStatus.ID,
CreatedAt: newStatus.CreatedAt.Format(time.RFC3339),
InReplyToID: newStatus.InReplyToID,
// InReplyToAccountID: newStatus.ReplyToAccount.ID,
Sensitive: newStatus.Sensitive,
SpoilerText: newStatus.ContentWarning,
Visibility: util.ParseMastoVisFromGTSVis(newStatus.Visibility),
Language: newStatus.Language,
URI: newStatus.URI,
URL: newStatus.URL,
Content: newStatus.Content,
Application: authed.Application.ToMastoPublic(),
Account: mastoAccount,
// MediaAttachments: ,
Text: form.Status,
ID: newStatus.ID,
CreatedAt: newStatus.CreatedAt.Format(time.RFC3339),
InReplyToID: newStatus.InReplyToID,
InReplyToAccountID: newStatus.InReplyToAccountID,
Sensitive: newStatus.Sensitive,
SpoilerText: newStatus.ContentWarning,
Visibility: mastoVis,
Language: newStatus.Language,
URI: newStatus.URI,
URL: newStatus.URL,
Content: newStatus.Content,
Application: mastoApplication,
Account: mastoAccount,
MediaAttachments: mastoAttachments,
Mentions: mastoMentions,
Text: form.Status,
}
c.JSON(http.StatusOK, mastoStatus)
}
@ -255,16 +293,16 @@ func validateCreateStatus(form *advancedStatusCreateForm, config *config.Statuse
return nil
}
func parseVisibility(form *advancedStatusCreateForm, accountDefaultVis model.Visibility, status *model.Status) error {
func parseVisibility(form *advancedStatusCreateForm, accountDefaultVis gtsmodel.Visibility, status *gtsmodel.Status) error {
// by default all flags are set to true
gtsAdvancedVis := &model.VisibilityAdvanced{
gtsAdvancedVis := &gtsmodel.VisibilityAdvanced{
Federated: true,
Boostable: true,
Replyable: true,
Likeable: true,
}
var gtsBasicVis model.Visibility
var gtsBasicVis gtsmodel.Visibility
// Advanced takes priority if it's set.
// If it's not set, take whatever masto visibility is set.
// If *that's* not set either, then just take the account default.
@ -277,10 +315,10 @@ func parseVisibility(form *advancedStatusCreateForm, accountDefaultVis model.Vis
}
switch gtsBasicVis {
case model.VisibilityPublic:
case gtsmodel.VisibilityPublic:
// for public, there's no need to change any of the advanced flags from true regardless of what the user filled out
break
case model.VisibilityUnlocked:
case gtsmodel.VisibilityUnlocked:
// for unlocked the user can set any combination of flags they like so look at them all to see if they're set and then apply them
if form.Federated != nil {
gtsAdvancedVis.Federated = *form.Federated
@ -298,7 +336,7 @@ func parseVisibility(form *advancedStatusCreateForm, accountDefaultVis model.Vis
gtsAdvancedVis.Likeable = *form.Likeable
}
case model.VisibilityFollowersOnly, model.VisibilityMutualsOnly:
case gtsmodel.VisibilityFollowersOnly, gtsmodel.VisibilityMutualsOnly:
// for followers or mutuals only, boostable will *always* be false, but the other fields can be set so check and apply them
gtsAdvancedVis.Boostable = false
@ -314,7 +352,7 @@ func parseVisibility(form *advancedStatusCreateForm, accountDefaultVis model.Vis
gtsAdvancedVis.Likeable = *form.Likeable
}
case model.VisibilityDirect:
case gtsmodel.VisibilityDirect:
// direct is pretty easy: there's only one possible setting so return it
gtsAdvancedVis.Federated = true
gtsAdvancedVis.Boostable = false
@ -327,7 +365,7 @@ func parseVisibility(form *advancedStatusCreateForm, accountDefaultVis model.Vis
return nil
}
func (m *statusModule) parseReplyToID(form *advancedStatusCreateForm, thisAccountID string, status *model.Status) error {
func (m *statusModule) parseReplyToID(form *advancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) error {
if form.InReplyToID == "" {
return nil
}
@ -339,8 +377,8 @@ func (m *statusModule) parseReplyToID(form *advancedStatusCreateForm, thisAccoun
// 3. Does a block exist between either the current account or the account that posted the status it's replying to?
//
// If this is all OK, then we fetch the repliedStatus and the repliedAccount for later processing.
repliedStatus := &model.Status{}
repliedAccount := &model.Account{}
repliedStatus := &gtsmodel.Status{}
repliedAccount := &gtsmodel.Account{}
// check replied status exists + is replyable
if err := m.db.GetByID(form.InReplyToID, repliedStatus); err != nil {
if _, ok := err.(db.ErrNoEntries); ok {
@ -356,26 +394,35 @@ func (m *statusModule) parseReplyToID(form *advancedStatusCreateForm, thisAccoun
// check replied account is known to us
if err := m.db.GetByID(repliedStatus.AccountID, repliedAccount); err != nil {
return fmt.Errorf("status with id %s not replyable: %s", form.InReplyToID, err)
if _, ok := err.(db.ErrNoEntries); ok {
return fmt.Errorf("status with id %s not replyable because account id %s is not known", form.InReplyToID, repliedStatus.AccountID)
} else {
return fmt.Errorf("status with id %s not replyable: %s", form.InReplyToID, err)
}
}
// check if a block exists
if blocked, err := m.db.Blocked(thisAccountID, repliedAccount.ID); err != nil || blocked {
return fmt.Errorf("status with id %s not replyable: %s", form.InReplyToID, err)
if blocked, err := m.db.Blocked(thisAccountID, repliedAccount.ID); err != nil {
if _, ok := err.(db.ErrNoEntries); !ok {
return fmt.Errorf("status with id %s not replyable: %s", form.InReplyToID, err)
}
} else if blocked {
return fmt.Errorf("status with id %s not replyable", form.InReplyToID)
}
status.InReplyToID = repliedStatus.ID
status.InReplyToAccountID = repliedAccount.ID
return nil
}
func (m *statusModule) parseMediaIDs(form *advancedStatusCreateForm, thisAccountID string, status *model.Status) error {
func (m *statusModule) parseMediaIDs(form *advancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) error {
if form.MediaIDs == nil {
return nil
}
attachments := []*model.MediaAttachment{}
attachments := []*gtsmodel.MediaAttachment{}
for _, mediaID := range form.MediaIDs {
// check these attachments exist
a := &model.MediaAttachment{}
a := &gtsmodel.MediaAttachment{}
if err := m.db.GetByID(mediaID, a); err != nil {
return fmt.Errorf("invalid media type or media not found for media id %s", mediaID)
}
@ -389,7 +436,7 @@ func (m *statusModule) parseMediaIDs(form *advancedStatusCreateForm, thisAccount
return nil
}
func parseLanguage(form *advancedStatusCreateForm, accountDefaultLanguage string, status *model.Status) error {
func parseLanguage(form *advancedStatusCreateForm, accountDefaultLanguage string, status *gtsmodel.Status) error {
if form.Language != "" {
status.Language = form.Language
} else {

View File

@ -34,12 +34,13 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/db/model"
"github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/distributor"
"github.com/superseriousbusiness/gotosocial/internal/mastotypes"
mastomodel "github.com/superseriousbusiness/gotosocial/internal/mastotypes/mastomodel"
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/storage"
"github.com/superseriousbusiness/gotosocial/pkg/mastotypes"
"github.com/superseriousbusiness/gotosocial/testrig"
)
@ -49,12 +50,13 @@ type StatusCreateTestSuite struct {
mockOauthServer *oauth.MockServer
mockStorage *storage.MockStorage
mediaHandler media.MediaHandler
mastoConverter mastotypes.Converter
distributor *distributor.MockDistributor
testTokens map[string]*oauth.Token
testClients map[string]*oauth.Client
testApplications map[string]*model.Application
testUsers map[string]*model.User
testAccounts map[string]*model.Account
testApplications map[string]*gtsmodel.Application
testUsers map[string]*gtsmodel.User
testAccounts map[string]*gtsmodel.Account
log *logrus.Logger
db db.DB
statusModule *statusModule
@ -113,10 +115,11 @@ func (suite *StatusCreateTestSuite) SetupSuite() {
suite.mockOauthServer = &oauth.MockServer{}
suite.mockStorage = &storage.MockStorage{}
suite.mediaHandler = media.New(suite.config, suite.db, suite.mockStorage, log)
suite.mastoConverter = mastotypes.New(suite.config, suite.db)
suite.distributor = &distributor.MockDistributor{}
suite.distributor.On("FromClientAPI").Return(make(chan distributor.FromClientAPI, 100))
suite.statusModule = New(suite.config, suite.db, suite.mockOauthServer, suite.mediaHandler, suite.distributor, suite.log).(*statusModule)
suite.statusModule = New(suite.config, suite.db, suite.mockOauthServer, suite.mediaHandler, suite.mastoConverter, suite.distributor, suite.log).(*statusModule)
}
func (suite *StatusCreateTestSuite) TearDownSuite() {
@ -184,16 +187,15 @@ func (suite *StatusCreateTestSuite) TestStatusCreatePOSTHandlerSuccessful() {
defer result.Body.Close()
b, err := ioutil.ReadAll(result.Body)
assert.NoError(suite.T(), err)
fmt.Println(string(b))
statusReply := &mastotypes.Status{}
statusReply := &mastomodel.Status{}
err = json.Unmarshal(b, statusReply)
assert.NoError(suite.T(), err)
assert.Equal(suite.T(), "hello hello", statusReply.SpoilerText)
assert.Equal(suite.T(), "this is a brand new status!", statusReply.Content)
assert.True(suite.T(), statusReply.Sensitive)
assert.Equal(suite.T(), mastotypes.VisibilityPrivate, statusReply.Visibility)
assert.Equal(suite.T(), mastomodel.VisibilityPrivate, statusReply.Visibility)
}
func (suite *StatusCreateTestSuite) TestStatusCreatePOSTHandlerReplyToFail() {
@ -209,31 +211,60 @@ func (suite *StatusCreateTestSuite) TestStatusCreatePOSTHandlerReplyToFail() {
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["local_account_1"])
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080/%s", basePath), nil) // the endpoint we're hitting
ctx.Request.Form = url.Values{
"status": {"this is a reply to a status that doesn't exist"},
"spoiler_text": {"don't open cuz it won't work"},
"in_reply_to_id": {"3759e7ef-8ee1-4c0c-86f6-8b70b9ad3d50"},
"status": {"this is a reply to a status that doesn't exist"},
"spoiler_text": {"don't open cuz it won't work"},
"in_reply_to_id": {"3759e7ef-8ee1-4c0c-86f6-8b70b9ad3d50"},
}
suite.statusModule.statusCreatePOSTHandler(ctx)
// check response
// 1. we should have OK from our call to the function
suite.EqualValues(http.StatusBadRequest, recorder.Code)
result := recorder.Result()
defer result.Body.Close()
b, err := ioutil.ReadAll(result.Body)
assert.NoError(suite.T(), err)
assert.Equal(suite.T(), `{"error":"status with id 3759e7ef-8ee1-4c0c-86f6-8b70b9ad3d50 not replyable because it doesn't exist"}`, string(b))
}
func (suite *StatusCreateTestSuite) TestStatusCreatePOSTHandlerReplyToLocalSuccess() {
t := suite.testTokens["local_account_1"]
oauthToken := oauth.PGTokenToOauthToken(t)
// setup
recorder := httptest.NewRecorder()
ctx, _ := gin.CreateTestContext(recorder)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["local_account_1"])
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080/%s", basePath), nil) // the endpoint we're hitting
ctx.Request.Form = url.Values{
"status": {fmt.Sprintf("hello @%s this reply should work!", testrig.TestAccounts()["local_account_2"].Username)},
"in_reply_to_id": {testrig.TestStatuses()["local_account_2_status_1"].ID},
}
suite.statusModule.statusCreatePOSTHandler(ctx)
// check response
suite.EqualValues(http.StatusOK, recorder.Code)
result := recorder.Result()
defer result.Body.Close()
b, err := ioutil.ReadAll(result.Body)
assert.NoError(suite.T(), err)
fmt.Println(string(b))
statusReply := &mastotypes.Status{}
statusReply := &mastomodel.Status{}
err = json.Unmarshal(b, statusReply)
assert.NoError(suite.T(), err)
assert.Equal(suite.T(), "hello hello", statusReply.SpoilerText)
assert.Equal(suite.T(), "this is a brand new status!", statusReply.Content)
assert.True(suite.T(), statusReply.Sensitive)
assert.Equal(suite.T(), mastotypes.VisibilityPrivate, statusReply.Visibility)
assert.Equal(suite.T(), "", statusReply.SpoilerText)
assert.Equal(suite.T(), fmt.Sprintf("hello @%s this reply should work!", testrig.TestAccounts()["local_account_2"].Username), statusReply.Content)
assert.False(suite.T(), statusReply.Sensitive)
assert.Equal(suite.T(), mastomodel.VisibilityPublic, statusReply.Visibility)
assert.Equal(suite.T(), testrig.TestStatuses()["local_account_2_status_1"].ID, statusReply.InReplyToID)
assert.Equal(suite.T(), testrig.TestAccounts()["local_account_2"].ID, statusReply.InReplyToAccountID)
assert.Len(suite.T(), statusReply.Mentions, 1)
}
func TestStatusCreateTestSuite(t *testing.T) {