mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 12:52:25 -05:00 
			
		
		
		
	start work on accounts module
This commit is contained in:
		
					parent
					
						
							
								aa9ce272dc
							
						
					
				
			
			
				commit
				
					
						7139116e5d
					
				
			
		
					 7 changed files with 133 additions and 6 deletions
				
			
		|  | @ -25,6 +25,7 @@ import ( | |||
| 
 | ||||
| 	"github.com/go-fed/activity/pub" | ||||
| 	"github.com/gotosocial/gotosocial/internal/config" | ||||
| 	"github.com/gotosocial/gotosocial/internal/gtsmodel" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
| 
 | ||||
|  | @ -68,6 +69,15 @@ type DB interface { | |||
| 
 | ||||
| 	// Delete where deletes i where key = value | ||||
| 	DeleteWhere(key string, value interface{}, i interface{}) error | ||||
| 
 | ||||
| 	// GetAccountByUserID is a shortcut for the common action of fetching an account corresponding to a user ID | ||||
| 	GetAccountByUserID(userID string, account *gtsmodel.Account) error | ||||
| 
 | ||||
| 	// GetFollowingByAccountID is a shortcut for the common action of fetching a list of accounts that accountID is following | ||||
| 	GetFollowingByAccountID(accountID string, following *[]gtsmodel.Follow) error | ||||
| 
 | ||||
| 	// GetFollowersByAccountID is a shortcut for the common action of fetching a list of accounts that accountID is followed by | ||||
| 	GetFollowersByAccountID(accountID string, following *[]gtsmodel.Follow) error | ||||
| } | ||||
| 
 | ||||
| // New returns a new database service that satisfies the DB interface and, by extension, | ||||
|  |  | |||
|  | @ -249,3 +249,21 @@ func (ps *postgresService) DeleteWhere(key string, value interface{}, i interfac | |||
| 	_, err := ps.conn.Model(i).Where(fmt.Sprintf("%s = ?", key), value).Delete() | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (ps *postgresService) GetAccountByUserID(userID string, account *gtsmodel.Account) error { | ||||
| 	user := >smodel.User{ | ||||
| 		ID: userID, | ||||
| 	} | ||||
| 	if err := ps.conn.Model(user).Where("id = ?", userID).Select(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return ps.conn.Model(account).Where("id = ?", user.AccountID).Select() | ||||
| } | ||||
| 
 | ||||
| func (ps *postgresService) GetFollowingByAccountID(accountID string, following *[]gtsmodel.Follow) error { | ||||
| 	return ps.conn.Model(following).Where("account_id = ?", accountID).Select() | ||||
| } | ||||
| 
 | ||||
| func (ps *postgresService) GetFollowersByAccountID(accountID string, following *[]gtsmodel.Follow) error { | ||||
| 	return ps.conn.Model(following).Where("target_account_id = ?", accountID).Select() | ||||
| } | ||||
|  |  | |||
|  | @ -24,6 +24,8 @@ package gtsmodel | |||
| import ( | ||||
| 	"net/url" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/gotosocial/gotosocial/pkg/mastotypes" | ||||
| ) | ||||
| 
 | ||||
| // Account represents either a local or a remote fediverse account, gotosocial or otherwise (mastodon, pleroma, etc) | ||||
|  | @ -63,6 +65,8 @@ type Account struct { | |||
| 	UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"` | ||||
| 	// When should this account function until | ||||
| 	SubscriptionExpiresAt time.Time `pg:"type:timestamp"` | ||||
| 	// Does this account identify itself as a bot? | ||||
| 	Bot bool | ||||
| 
 | ||||
| 	/* | ||||
| 		PRIVACY SETTINGS | ||||
|  | @ -153,3 +157,22 @@ type Header struct { | |||
| 	HeaderRemoteURL            *url.URL `pg:"type:text"` | ||||
| 	HeaderStorageSchemaVersion int | ||||
| } | ||||
| 
 | ||||
| // ToMastoSensitive returns this account as a mastodon api type, ready for serialization | ||||
| func (a *Account) ToMastoSensitive() *mastotypes.Account { | ||||
| 	return &mastotypes.Account{ | ||||
| 		ID:           a.ID, | ||||
| 		Username:     a.Username, | ||||
| 		Acct:         a.Username, // equivalent to username for local users only, which sensitive always is | ||||
| 		DisplayName:  a.DisplayName, | ||||
| 		Locked:       a.Locked, | ||||
| 		Bot:          a.Bot, | ||||
| 		CreatedAt:    a.CreatedAt.Format(time.RFC3339), | ||||
| 		Note:         a.Note, | ||||
| 		URL:          a.URL, | ||||
| 		Avatar:       a.Avatar.AvatarRemoteURL.String(), | ||||
| 		AvatarStatic: a.AvatarRemoteURL.String(), | ||||
| 		Header:       a.Header.HeaderRemoteURL.String(), | ||||
| 		HeaderStatic: a.Header.HeaderRemoteURL.String(), | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -41,8 +41,8 @@ type Application struct { | |||
| 	VapidKey string | ||||
| } | ||||
| 
 | ||||
| // ToMastotype returns this application as a mastodon api type, ready for serialization | ||||
| func (a *Application) ToMastotype() *mastotypes.Application { | ||||
| // ToMasto returns this application as a mastodon api type, ready for serialization | ||||
| func (a *Application) ToMasto() *mastotypes.Application { | ||||
| 	return &mastotypes.Application{ | ||||
| 		ID:           a.ID, | ||||
| 		Name:         a.Name, | ||||
|  |  | |||
							
								
								
									
										38
									
								
								internal/gtsmodel/follow.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								internal/gtsmodel/follow.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | |||
| /* | ||||
|    GoToSocial | ||||
|    Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org | ||||
| 
 | ||||
|    This program is free software: you can redistribute it and/or modify | ||||
|    it under the terms of the GNU Affero General Public License as published by | ||||
|    the Free Software Foundation, either version 3 of the License, or | ||||
|    (at your option) any later version. | ||||
| 
 | ||||
|    This program is distributed in the hope that it will be useful, | ||||
|    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|    GNU Affero General Public License for more details. | ||||
| 
 | ||||
|    You should have received a copy of the GNU Affero General Public License | ||||
|    along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
| 
 | ||||
| package gtsmodel | ||||
| 
 | ||||
| import "time" | ||||
| 
 | ||||
| type Follow struct { | ||||
| 	// id of this follow in the database | ||||
| 	ID string `pg:"type:uuid,default:gen_random_uuid(),pk,notnull,unique"` | ||||
| 	// When was this follow created? | ||||
| 	CreatedAt time.Time `pg:"type:timestamp,notnull,default:now()"` | ||||
| 	// When was this follow last updated? | ||||
| 	UpdatedAt time.Time `pg:"type:timestamp,notnull,default:now()"` | ||||
| 	// Who does this follow belong to? | ||||
| 	AccountID string `pg:",unique:srctarget,notnull"` | ||||
| 	// Who does AccountID follow? | ||||
| 	TargetAccountID string `pg:",unique:srctarget,notnull"` | ||||
| 	// Does this follow also want to see reblogs and not just posts? | ||||
| 	ShowReblogs bool `pg:"default:true"` | ||||
| 	// What is the activitypub URI of this follow? | ||||
| 	URI string `pg:",unique"` | ||||
| } | ||||
|  | @ -19,19 +19,56 @@ | |||
| package account | ||||
| 
 | ||||
| import ( | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"github.com/gin-contrib/sessions" | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"github.com/gotosocial/gotosocial/internal/config" | ||||
| 	"github.com/gotosocial/gotosocial/internal/db" | ||||
| 	"github.com/gotosocial/gotosocial/internal/gtsmodel" | ||||
| 	"github.com/gotosocial/gotosocial/internal/module" | ||||
| 	"github.com/gotosocial/gotosocial/internal/module/oauth" | ||||
| 	"github.com/gotosocial/gotosocial/internal/router" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	basePath       = "/api/v1/accounts" | ||||
| 	basePathWithID = basePath + "/:id" | ||||
| 	verifyPath     = basePath + "/verify_credentials" | ||||
| ) | ||||
| 
 | ||||
| type accountModule struct { | ||||
| 	config *config.Config | ||||
| 	db     db.DB | ||||
| } | ||||
| 
 | ||||
| // New returns a new account module | ||||
| func New() module.ClientAPIModule { | ||||
| 	return &accountModule{} | ||||
| func New(config *config.Config, db db.DB) module.ClientAPIModule { | ||||
| 	return &accountModule{ | ||||
| 		config: config, | ||||
| 		db:     db, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Route attaches all routes from this module to the given router | ||||
| func (m *accountModule) Route(r router.Router) error { | ||||
| 	r.AttachHandler(http.MethodGet, verifyPath, m.AccountVerifyGETHandler) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (m *accountModule) AccountVerifyGETHandler(c *gin.Context) { | ||||
| 	s := sessions.Default(c) | ||||
| 	userID, ok := s.Get(oauth.SessionAuthorizedUser).(string) | ||||
| 	if !ok || userID == "" { | ||||
| 		c.JSON(http.StatusUnauthorized, gin.H{"error": "The access token is invalid"}) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	acct := >smodel.Account{} | ||||
| 	if err := m.db.GetAccountByUserID(userID, acct); err != nil { | ||||
| 		c.JSON(http.StatusInternalServerError, gin.H{"error": err}) | ||||
|       return | ||||
| 	} | ||||
| 
 | ||||
|    c.JSON(http.StatusOK, acct.ToMastoSensitive()) | ||||
| } | ||||
|  |  | |||
|  | @ -51,6 +51,7 @@ const ( | |||
| 	authSignInPath     = "/auth/sign_in" | ||||
| 	oauthTokenPath     = "/oauth/token" | ||||
| 	oauthAuthorizePath = "/oauth/authorize" | ||||
| 	SessionAuthorizedUser = "authorized_user" | ||||
| ) | ||||
| 
 | ||||
| // oauthModule is an oauth2 oauthModule that satisfies the ClientAPIModule interface | ||||
|  | @ -209,7 +210,7 @@ func (m *oauthModule) appsPOSTHandler(c *gin.Context) { | |||
| 	} | ||||
| 
 | ||||
| 	// done, return the new app information per the spec here: https://docs.joinmastodon.org/methods/apps/ | ||||
| 	c.JSON(http.StatusOK, app.ToMastotype()) | ||||
| 	c.JSON(http.StatusOK, app.ToMasto()) | ||||
| } | ||||
| 
 | ||||
| // signInGETHandler should be served at https://example.org/auth/sign_in. | ||||
|  | @ -411,7 +412,7 @@ func (m *oauthModule) oauthTokenMiddleware(c *gin.Context) { | |||
| 	l.Trace("entering OauthTokenMiddleware") | ||||
| 	if ti, err := m.oauthServer.ValidationBearerToken(c.Request); err == nil { | ||||
| 		l.Tracef("authenticated user %s with bearer token, scope is %s", ti.GetUserID(), ti.GetScope()) | ||||
| 		c.Set("authenticated_user", ti.GetUserID()) | ||||
| 		c.Set(SessionAuthorizedUser, ti.GetUserID()) | ||||
| 
 | ||||
| 	} else { | ||||
| 		l.Trace("continuing with unauthenticated request") | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue