kopia lustrzana https://github.com/reiver/greatape
feat(app): ✨ profile access control & refinements
rodzic
5f0929e0ae
commit
166f904b29
|
@ -19,6 +19,20 @@ type Note struct {
|
|||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
func NewNote(from, to, content string) *Note {
|
||||
return &Note{
|
||||
Context: "https://www.w3.org/ns/activitystreams",
|
||||
To: []string{to},
|
||||
Content: content,
|
||||
Type: "Note",
|
||||
AttributedTo: from,
|
||||
}
|
||||
}
|
||||
|
||||
func NewPublicNote(from, content string) *Note {
|
||||
return NewNote(from, "https://www.w3.org/ns/activitystreams#Public", content)
|
||||
}
|
||||
|
||||
func (note *Note) Wrap(username string) *Activity {
|
||||
return &Activity{
|
||||
Context: ActivityStreams,
|
||||
|
|
|
@ -15,13 +15,7 @@ func main() {
|
|||
|
||||
storage := db.CreateStorage(db.SqliteStorage)
|
||||
storage.Connect(config.SQLITE_DB)
|
||||
storage.Migrate(
|
||||
&repos.User{},
|
||||
&repos.IncomingActivity{},
|
||||
&repos.OutgoingActivity{},
|
||||
&repos.Follower{},
|
||||
&repos.Following{},
|
||||
)
|
||||
storage.Migrate(repos.All...)
|
||||
|
||||
app := server.New()
|
||||
app.SetStorageProvider(storage)
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package repos
|
||||
|
||||
var All = []interface{}{
|
||||
&User{},
|
||||
&IncomingActivity{},
|
||||
&OutgoingActivity{},
|
||||
&Follower{},
|
||||
&Following{},
|
||||
}
|
|
@ -6,6 +6,13 @@ import (
|
|||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Access int64
|
||||
|
||||
const (
|
||||
ACCESS_PUBLIC Access = iota
|
||||
ACCESS_PRIVATE
|
||||
)
|
||||
|
||||
// User struct defines the user
|
||||
type User struct {
|
||||
gorm.Model
|
||||
|
@ -20,6 +27,7 @@ type User struct {
|
|||
PublicKey string
|
||||
Avatar string
|
||||
Banner string
|
||||
Access Access
|
||||
}
|
||||
|
||||
// CreateUser create a user entry in the user's table
|
||||
|
|
|
@ -9,9 +9,11 @@ import (
|
|||
// Follower struct defines a follower
|
||||
type Follower struct {
|
||||
gorm.Model
|
||||
Target string `gorm:"not null"`
|
||||
Handle string `gorm:"not null"`
|
||||
Accepted bool `gorm:"not null"`
|
||||
Target string `gorm:"not null"`
|
||||
Handle string `gorm:"not null"`
|
||||
HandleInbox string
|
||||
Activity string
|
||||
Accepted bool
|
||||
}
|
||||
|
||||
// CreateFollower creates a new entry in the followers's table
|
||||
|
@ -24,6 +26,16 @@ func FindFollowers(dest interface{}, userIden interface{}) *gorm.DB {
|
|||
return db.Executor.Model(&Follower{}).Find(dest, "`target` = ?", userIden)
|
||||
}
|
||||
|
||||
// FindFollower searches the follower's table with the condition given
|
||||
func FindFollower(dest interface{}, conds ...interface{}) *gorm.DB {
|
||||
return db.Executor.Model(&Follower{}).Take(dest, conds...)
|
||||
}
|
||||
|
||||
// FindFollowerById searches the followers's table with the id given
|
||||
func FindFollowerById(dest interface{}, id uint64) *gorm.DB {
|
||||
return FindFollower(dest, "id = ?", id)
|
||||
}
|
||||
|
||||
// AcceptFollower accepts a follow request
|
||||
func AcceptFollower(id interface{}) *gorm.DB {
|
||||
return db.Executor.Model(&Follower{}).Where("id = ?", id).Update("accepted", true)
|
||||
|
|
|
@ -6,7 +6,12 @@ import (
|
|||
"app/models/types"
|
||||
"config"
|
||||
. "contracts"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"server/route"
|
||||
"strconv"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var Followers = route.New(HttpGet, "/u/:username/followers", func(x IContext) error {
|
||||
|
@ -39,10 +44,39 @@ var Followers = route.New(HttpGet, "/u/:username/followers", func(x IContext) er
|
|||
})
|
||||
|
||||
var AcceptFollowRequest = route.New(HttpPut, "/u/:username/followers/:id/accept", func(x IContext) error {
|
||||
username := x.Request().Params("username")
|
||||
id := x.Request().Params("id")
|
||||
|
||||
err := repos.AcceptFollower(id).Error
|
||||
followerId, err := strconv.ParseUint(id, 10, 64)
|
||||
if err != nil {
|
||||
return x.BadRequest("invalid_id")
|
||||
}
|
||||
|
||||
follower := &repos.Follower{}
|
||||
if err := repos.FindFollowerById(follower, followerId).Error; err != nil {
|
||||
return x.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
data, _ := json.Marshal(&activitypub.Activity{
|
||||
Context: "https://www.w3.org/ns/activitystreams",
|
||||
ID: x.StringUtil().Format("%s://%s/%s", config.PROTOCOL, config.DOMAIN, x.GUID()),
|
||||
Type: activitypub.TypeAccept,
|
||||
Actor: x.StringUtil().Format("%s://%s/u/%s", config.PROTOCOL, config.DOMAIN, username),
|
||||
Object: follower.Activity,
|
||||
})
|
||||
|
||||
user := &repos.User{}
|
||||
err = repos.FindUserByUsername(user, username).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return x.NotFound("No record found for %s.", username)
|
||||
}
|
||||
|
||||
keyId := x.StringUtil().Format("%s://%s/u/%s#main-key", config.PROTOCOL, config.DOMAIN, username)
|
||||
|
||||
if err := x.PostActivityStream(follower.HandleInbox, keyId, user.PrivateKey, data, nil); err != nil {
|
||||
return x.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
if err := repos.AcceptFollower(follower.ID).Error; err != nil {
|
||||
return x.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ var InboxPost = route.New(HttpPost, "/u/:username/inbox", func(x IContext) error
|
|||
return x.BadRequest("Bad request")
|
||||
}
|
||||
|
||||
key := &types.KeyResponse{}
|
||||
err := repos.FindUserByUsername(key, username).Error
|
||||
user := &repos.User{}
|
||||
err := repos.FindUserByUsername(user, username).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return x.NotFound("No record found for %s.", username)
|
||||
}
|
||||
|
@ -40,19 +40,35 @@ var InboxPost = route.New(HttpPost, "/u/:username/inbox", func(x IContext) error
|
|||
}
|
||||
|
||||
url := activity.Actor
|
||||
follower := activity.Actor
|
||||
var inbox string
|
||||
|
||||
{
|
||||
actor := &activitypub.Actor{}
|
||||
if err := x.GetActivityStream(url, keyId, key.PrivateKey, nil, actor); err != nil {
|
||||
if err := x.GetActivityStream(url, keyId, user.PrivateKey, nil, actor); err != nil {
|
||||
return x.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
inbox = actor.Inbox
|
||||
}
|
||||
|
||||
{
|
||||
data, err := json.Marshal(activity)
|
||||
if err != nil {
|
||||
return x.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
follower := &repos.Follower{
|
||||
Target: x.StringUtil().Format("%s://%s/u/%s", config.PROTOCOL, config.DOMAIN, username),
|
||||
Handle: activity.Actor,
|
||||
HandleInbox: inbox,
|
||||
Activity: string(data),
|
||||
Accepted: false,
|
||||
}
|
||||
|
||||
if err := repos.CreateFollower(follower); err.Error != nil {
|
||||
return x.Conflict(err.Error.Error())
|
||||
}
|
||||
|
||||
if user.Access == repos.ACCESS_PUBLIC {
|
||||
data, _ := json.Marshal(&activitypub.Activity{
|
||||
Context: "https://www.w3.org/ns/activitystreams",
|
||||
ID: x.StringUtil().Format("%s://%s/%s", config.PROTOCOL, config.DOMAIN, x.GUID()),
|
||||
|
@ -61,16 +77,13 @@ var InboxPost = route.New(HttpPost, "/u/:username/inbox", func(x IContext) error
|
|||
Object: activity,
|
||||
})
|
||||
|
||||
if err := x.PostActivityStream(inbox, keyId, key.PrivateKey, data, nil); err != nil {
|
||||
if err := x.PostActivityStream(inbox, keyId, user.PrivateKey, data, nil); err != nil {
|
||||
return x.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
if err := repos.CreateFollower(&repos.Follower{
|
||||
Target: x.StringUtil().Format("%s://%s/u/%s", config.PROTOCOL, config.DOMAIN, username),
|
||||
Handle: follower,
|
||||
Accepted: true,
|
||||
}); err.Error != nil {
|
||||
return x.Conflict(err.Error.Error())
|
||||
err := repos.AcceptFollower(follower.ID).Error
|
||||
if err != nil {
|
||||
return x.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,16 +140,7 @@ var InboxGet = route.New(HttpGet, "/u/:username/inbox", func(x IContext) error {
|
|||
|
||||
items := []*activitypub.Activity{}
|
||||
for _, message := range *messages {
|
||||
note := &activitypub.Note{
|
||||
Context: "https://www.w3.org/ns/activitystreams",
|
||||
To: []string{
|
||||
"https://www.w3.org/ns/activitystreams#Public",
|
||||
},
|
||||
Content: message.Content,
|
||||
Type: "Note",
|
||||
AttributedTo: message.From,
|
||||
}
|
||||
|
||||
note := activitypub.NewPublicNote(message.From, message.Content)
|
||||
activity := note.Wrap(username)
|
||||
items = append(items, activity)
|
||||
}
|
||||
|
|
|
@ -89,16 +89,7 @@ var OutboxGet = route.New(HttpGet, "/u/:username/outbox", func(x IContext) error
|
|||
|
||||
items := []*activitypub.Activity{}
|
||||
for _, message := range *messages {
|
||||
note := &activitypub.Note{
|
||||
Context: "https://www.w3.org/ns/activitystreams",
|
||||
To: []string{
|
||||
"https://www.w3.org/ns/activitystreams#Public",
|
||||
},
|
||||
Content: message.Content,
|
||||
Type: "Note",
|
||||
AttributedTo: actor,
|
||||
}
|
||||
|
||||
note := activitypub.NewPublicNote(actor, message.Content)
|
||||
activity := note.Wrap(username)
|
||||
items = append(items, activity)
|
||||
}
|
||||
|
|
|
@ -19,13 +19,7 @@ func TestMain(m *testing.M) {
|
|||
|
||||
storage := db.CreateStorage(db.SqliteStorage)
|
||||
storage.Connect(config.SQLITE_DB)
|
||||
storage.Migrate(
|
||||
&repos.User{},
|
||||
&repos.IncomingActivity{},
|
||||
&repos.OutgoingActivity{},
|
||||
&repos.Follower{},
|
||||
&repos.Following{},
|
||||
)
|
||||
storage.Migrate(repos.All...)
|
||||
|
||||
app := server.New()
|
||||
app.SetStorageProvider(storage)
|
||||
|
|
Ładowanie…
Reference in New Issue