feat(app): enhance public profile

master
Xeronith 2022-08-15 22:02:39 +04:30
rodzic 1fa79a084d
commit f5b4ebe171
9 zmienionych plików z 180 dodań i 20 usunięć

Wyświetl plik

@ -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)
}

Wyświetl plik

@ -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)
}

Wyświetl plik

@ -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)
}

Wyświetl plik

@ -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"`
}

Wyświetl plik

@ -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"`
}

Wyświetl plik

@ -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))
})

Wyświetl plik

@ -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))
})

Wyświetl plik

@ -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()

Wyświetl plik

@ -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>