kopia lustrzana https://github.com/reiver/greatape
feat(app): ✨ enhance public profile
rodzic
1fa79a084d
commit
f5b4ebe171
|
@ -0,0 +1,21 @@
|
|||
package activitypub
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type Followers struct {
|
||||
Context string `json:"@context"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
TotalItems int `json:"totalItems"`
|
||||
OrderedItems interface{} `json:"orderedItems,omitempty"`
|
||||
}
|
||||
|
||||
func UnmarshalFollowers(data []byte) (Followers, error) {
|
||||
var o Followers
|
||||
err := json.Unmarshal(data, &o)
|
||||
return o, err
|
||||
}
|
||||
|
||||
func (o *Followers) Marshal() ([]byte, error) {
|
||||
return json.Marshal(o)
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
// Follower struct defines a follower
|
||||
type Follower struct {
|
||||
gorm.Model
|
||||
Target string `gorm:"not null"`
|
||||
Handle string `gorm:"not null"`
|
||||
}
|
||||
|
||||
|
@ -16,3 +17,8 @@ type Follower struct {
|
|||
func CreateFollower(follower *Follower) *gorm.DB {
|
||||
return db.DB.Create(follower)
|
||||
}
|
||||
|
||||
// FindFollowers finds the user's followers
|
||||
func FindFollowers(dest interface{}, userIden interface{}) *gorm.DB {
|
||||
return db.DB.Model(&Follower{}).Find(dest, "`target` = ?", userIden)
|
||||
}
|
||||
|
|
|
@ -6,13 +6,19 @@ import (
|
|||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Following struct defines a follower
|
||||
// Following struct defines an account that the user follows
|
||||
type Following struct {
|
||||
gorm.Model
|
||||
Target string `gorm:"not null"`
|
||||
Handle string `gorm:"not null"`
|
||||
}
|
||||
|
||||
// CreateFollowing creates a new entry in the followers's table
|
||||
// CreateFollowing creates a new entry in the following's table
|
||||
func CreateFollowing(following *Following) *gorm.DB {
|
||||
return db.DB.Create(following)
|
||||
}
|
||||
|
||||
// FindFollowing finds what accounts the user is following
|
||||
func FindFollowing(dest interface{}, userIden interface{}) *gorm.DB {
|
||||
return db.DB.Model(&Follower{}).Find(dest, "`handle` = ?", userIden)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package types
|
||||
|
||||
type FollowerDTO struct {
|
||||
Target string `json:"target" validate:"required"`
|
||||
Handle string `json:"handle" validate:"required"`
|
||||
}
|
||||
|
||||
type FollowerResponse struct {
|
||||
Handler string `json:"handler"`
|
||||
Target string `json:"target"`
|
||||
Handle string `json:"handle"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package types
|
||||
|
||||
type FollowingDTO struct {
|
||||
Target string `json:"target" validate:"required"`
|
||||
Handle string `json:"handle" validate:"required"`
|
||||
}
|
||||
|
||||
type FollowingResponse struct {
|
||||
Target string `json:"target"`
|
||||
Handle string `json:"handle"`
|
||||
}
|
|
@ -1,10 +1,39 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"app/activitypub"
|
||||
"app/models/repos"
|
||||
"app/models/types"
|
||||
"config"
|
||||
. "contracts"
|
||||
"server/route"
|
||||
)
|
||||
|
||||
var Followers = route.New(HttpGet, "/u/:name/followers", func(x IContext) error {
|
||||
return x.JSON(struct{}{})
|
||||
var Followers = route.New(HttpGet, "/u/:username/followers", func(x IContext) error {
|
||||
username := x.Request().Params("username")
|
||||
actor := x.StringUtil().Format("%s://%s/u/%s", config.PROTOCOL, config.DOMAIN, username)
|
||||
id := x.StringUtil().Format("%s://%s/u/%s/followers", config.PROTOCOL, config.DOMAIN, username)
|
||||
|
||||
followers := &[]types.FollowerResponse{}
|
||||
err := repos.FindFollowers(followers, actor).Error
|
||||
if err != nil {
|
||||
x.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
items := []string{}
|
||||
for _, follower := range *followers {
|
||||
items = append(items, follower.Handle)
|
||||
}
|
||||
|
||||
result := &activitypub.Followers{
|
||||
Context: "https://www.w3.org/ns/activitystreams",
|
||||
ID: id,
|
||||
Type: "OrderedCollection",
|
||||
TotalItems: len(items),
|
||||
OrderedItems: items,
|
||||
}
|
||||
|
||||
json, _ := result.Marshal()
|
||||
x.Response().Header("Content-Type", "application/activity+json; charset=utf-8")
|
||||
return x.WriteString(string(json))
|
||||
})
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"app/activitypub"
|
||||
"app/models/repos"
|
||||
"app/models/types"
|
||||
"config"
|
||||
. "contracts"
|
||||
"server/route"
|
||||
)
|
||||
|
||||
var Following = route.New(HttpGet, "/u/:username/following", func(x IContext) error {
|
||||
username := x.Request().Params("username")
|
||||
actor := x.StringUtil().Format("%s://%s/u/%s", config.PROTOCOL, config.DOMAIN, username)
|
||||
id := x.StringUtil().Format("%s://%s/u/%s/following", config.PROTOCOL, config.DOMAIN, username)
|
||||
|
||||
followings := &[]types.FollowerResponse{}
|
||||
err := repos.FindFollowing(followings, actor).Error
|
||||
if err != nil {
|
||||
x.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
items := []string{}
|
||||
for _, following := range *followings {
|
||||
items = append(items, following.Target)
|
||||
}
|
||||
|
||||
result := &activitypub.Followers{
|
||||
Context: "https://www.w3.org/ns/activitystreams",
|
||||
ID: id,
|
||||
Type: "OrderedCollection",
|
||||
TotalItems: len(items),
|
||||
OrderedItems: items,
|
||||
}
|
||||
|
||||
json, _ := result.Marshal()
|
||||
x.Response().Header("Content-Type", "application/activity+json; charset=utf-8")
|
||||
return x.WriteString(string(json))
|
||||
})
|
|
@ -40,6 +40,7 @@ var InboxPost = route.New(HttpPost, "/u/:username/inbox", func(x IContext) error
|
|||
}
|
||||
|
||||
url := activity.Actor
|
||||
follower := activity.Actor
|
||||
var inbox string
|
||||
|
||||
{
|
||||
|
@ -60,13 +61,16 @@ var InboxPost = route.New(HttpPost, "/u/:username/inbox", func(x IContext) error
|
|||
Object: activity,
|
||||
})
|
||||
|
||||
output := &struct {
|
||||
content string
|
||||
}{}
|
||||
|
||||
if err := x.PostActivityStream(inbox, keyId, key.PrivateKey, data, output); err != nil {
|
||||
if err := x.PostActivityStream(inbox, keyId, key.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,
|
||||
}); err.Error != nil {
|
||||
return x.Conflict(err.Error.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return x.Nothing()
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<h1 class="display-3">{{ .Title }}</h1>
|
||||
<br />
|
||||
<h1 class="display-5">{{ .Title }}</h1>
|
||||
<br />
|
||||
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button
|
||||
|
@ -87,7 +89,7 @@
|
|||
>
|
||||
<div class="container">
|
||||
<br />
|
||||
Followers
|
||||
<ul id="followers"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
@ -98,14 +100,14 @@
|
|||
tabindex="0"
|
||||
>
|
||||
<br />
|
||||
Following
|
||||
<ul id="following"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function refreshFeed() {
|
||||
function refresh() {
|
||||
axios({
|
||||
method: "get",
|
||||
url: "/u/{{ .Username }}/outbox",
|
||||
|
@ -113,9 +115,8 @@
|
|||
Authorization: "Bearer " + localStorage.getItem("token"),
|
||||
},
|
||||
}).then(function (response) {
|
||||
console.log(response);
|
||||
const feed = document.getElementById("feed");
|
||||
feed.innerHTML = "";
|
||||
const list = document.getElementById("feed");
|
||||
list.innerHTML = "";
|
||||
for (let i = 0; i < response.data.orderedItems.length; i++) {
|
||||
let item = document.createElement("li");
|
||||
item.innerHTML =
|
||||
|
@ -124,13 +125,54 @@
|
|||
"</em><hr><p>" +
|
||||
response.data.orderedItems[i].object.content +
|
||||
"</p></article>";
|
||||
item.className = "list-group-item";
|
||||
feed.appendChild(item);
|
||||
list.appendChild(item);
|
||||
}
|
||||
});
|
||||
|
||||
axios({
|
||||
method: "get",
|
||||
url: "/u/{{ .Username }}/followers",
|
||||
headers: {
|
||||
Authorization: "Bearer " + localStorage.getItem("token"),
|
||||
},
|
||||
}).then(function (response) {
|
||||
const list = document.getElementById("followers");
|
||||
list.innerHTML = "";
|
||||
for (let i = 0; i < response.data.orderedItems.length; i++) {
|
||||
let item = document.createElement("li");
|
||||
item.innerHTML =
|
||||
'<article><p><a href="' +
|
||||
response.data.orderedItems[i] +
|
||||
'">' +
|
||||
response.data.orderedItems[i] +
|
||||
"</a></p></article>";
|
||||
list.appendChild(item);
|
||||
}
|
||||
});
|
||||
|
||||
axios({
|
||||
method: "get",
|
||||
url: "/u/{{ .Username }}/following",
|
||||
headers: {
|
||||
Authorization: "Bearer " + localStorage.getItem("token"),
|
||||
},
|
||||
}).then(function (response) {
|
||||
const list = document.getElementById("following");
|
||||
list.innerHTML = "";
|
||||
for (let i = 0; i < response.data.orderedItems.length; i++) {
|
||||
let item = document.createElement("li");
|
||||
item.innerHTML =
|
||||
'<article><p><a href="' +
|
||||
response.data.orderedItems[i] +
|
||||
'">' +
|
||||
response.data.orderedItems[i] +
|
||||
"</a></p></article>";
|
||||
list.appendChild(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
refreshFeed();
|
||||
refresh();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Ładowanie…
Reference in New Issue