Federation (#327)
* initial commit federation * more federation * more federation * more federation * completes follow, accept, undo * add trail create activity * process trail create activity * more trail create activity * adds missing endpoints * adds update and delete activity * adds comment activities * adds activities back * adds summit logs activities * deletes follow counts table * fixes migrations * fixes migrations * fixes migrations * fixes migrations * adds remote profiles * ctd * ctd * we are getting closer... * adds public summit logs * fixes federated trails in lists * adds remote lists * adds list activites * fixes lists * adds notifications * adds iri redirect * fixes comments and summitlogs * fixes follows and profiles * adds asynchronous send * fixes list search * adds encryption key * bug fixes * fixes activity signing * removes custon activity object types * adds html editor * fixes html editor * fixes display issues on mastodon * adds federated sharing * finishes announcements * fixes small summit log issues * adds trail likes * finalizes likes * fixes images for komoot * add disable federation option * adds private profiles * updates docs * adds federated comments * adds trail and comments actvitiypub routes * adds mentions to editor * adds mentions to trails, comments, summit logs * updates theme * updates theme * update docs * update docs * updates docs * fixes various frontend problems * fixes activitypub follows api * updates docs * updates docs --------- Co-authored-by: Christian Beutel <>
This commit is contained in:
@@ -251,7 +251,7 @@ This release contains breaking changes. Most migrations will happen automaticall
|
|||||||
- Fixes issue with GPX export when using Google Chrome (thanks [@tofublock](https://github.com/tofublock))
|
- Fixes issue with GPX export when using Google Chrome (thanks [@tofublock](https://github.com/tofublock))
|
||||||
|
|
||||||
## Miscellaneous
|
## Miscellaneous
|
||||||
As the number of contributors to this project continues to grow (which I’m very happy about), I’ve set up a [Discord channel](https://discord.gg/MdpybUHc) for more direct communication. If you’re interested in helping with Wanderer, feel free to join!
|
As the number of contributors to this project continues to grow (which I’m very happy about), I’ve set up a [Discord channel](https://discord.gg/MdpybUHc) for more direct communication. If you’re interested in helping with wanderer, feel free to join!
|
||||||
|
|
||||||
# v0.11.0
|
# v0.11.0
|
||||||
## Features
|
## Features
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ The first startup can take up to 90 seconds after which you can access the front
|
|||||||
|
|
||||||
> ⚠️ if you are using wanderer in a production environment make sure to change the MEILI_MASTER_KEY variable.
|
> ⚠️ if you are using wanderer in a production environment make sure to change the MEILI_MASTER_KEY variable.
|
||||||
|
|
||||||
You can also run wanderer on bare-metal. Check out the [documentation](https://wanderer.to/getting-started/installation/#from-source) for a detailed how-to guide.
|
You can also run wanderer on bare-metal. Check out the [documentation](https://wanderer.to/run/installation/#installation-from-source) for a detailed how-to guide.
|
||||||
|
|
||||||
## Support wanderer
|
## Support wanderer
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ FROM alpine:3.16
|
|||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|
||||||
COPY migrations ./migrations
|
COPY migrations ./migrations
|
||||||
|
COPY templates ./templates
|
||||||
|
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
RUN echo ${TARGETARCH}
|
RUN echo ${TARGETARCH}
|
||||||
|
|||||||
207
db/federation/activity.go
Normal file
207
db/federation/activity.go
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
package federation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/x509"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
pub "github.com/go-ap/activitypub"
|
||||||
|
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/go-ap/jsonld"
|
||||||
|
"github.com/go-fed/httpsig"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
"golang.org/x/sync/semaphore"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PostActivity(app core.App, actor *core.Record, activity *pub.Activity, recipients []string) error {
|
||||||
|
encryptionKey := os.Getenv("POCKETBASE_ENCRYPTION_KEY")
|
||||||
|
if len(encryptionKey) == 0 {
|
||||||
|
return fmt.Errorf("POCKETBASE_ENCRYPTION_KEY not set")
|
||||||
|
}
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
algs := []httpsig.Algorithm{httpsig.RSA_SHA256}
|
||||||
|
postHeaders := []string{"(request-target)", "Date", "Digest", "Content-Type", "Host"}
|
||||||
|
expiresIn := 60
|
||||||
|
|
||||||
|
body, err := jsonld.WithContext(
|
||||||
|
jsonld.IRI(pub.ActivityBaseURI),
|
||||||
|
jsonld.IRI(pub.SecurityContextURI),
|
||||||
|
).Marshal(activity)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptedPrivateKey, err := security.Decrypt(actor.GetString("private_key"), encryptionKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
privateKey, err := x509.ParsePKCS1PrivateKey(decryptedPrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pubID := actor.GetString("iri") + "#main-key"
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
sem := semaphore.NewWeighted(5) // Limit to 5 concurrent sends
|
||||||
|
|
||||||
|
slices.Sort(recipients)
|
||||||
|
uniqueRecipients := slices.Compact(recipients)
|
||||||
|
|
||||||
|
for _, v := range uniqueRecipients {
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func(inbox string) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
signer, _, err := httpsig.NewSigner(algs, httpsig.DigestSha256, postHeaders, httpsig.Signature, int64(expiresIn))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sem.Acquire(context.Background(), 1); err != nil {
|
||||||
|
app.Logger().Error(fmt.Sprintf("Semaphore acquire failed: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer sem.Release(1)
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(body)
|
||||||
|
req, err := http.NewRequest(http.MethodPost, inbox, buf)
|
||||||
|
if err != nil {
|
||||||
|
app.Logger().Error(fmt.Sprintf("Request creation failed: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Header.Add("Content-Type", "application/activity+json")
|
||||||
|
req.Header.Add("Date", strings.ReplaceAll(time.Now().UTC().Format(time.RFC1123), "UTC", "GMT"))
|
||||||
|
req.Header.Add("Host", req.Host)
|
||||||
|
|
||||||
|
if err := signer.SignRequest(privateKey, pubID, req, body); err != nil {
|
||||||
|
app.Logger().Error(fmt.Sprintf("Signing request failed: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
app.Logger().Error(fmt.Sprintf("Error sending request to inbox %s: %s", inbox, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
app.Logger().Error(fmt.Sprintf("Inbox %s responded with %d: %s", inbox, resp.StatusCode, body))
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Logger().Info(fmt.Sprintf("Sent %s to %s", activity.Type, inbox))
|
||||||
|
}(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProcessActivity(e *core.RequestEvent) error {
|
||||||
|
|
||||||
|
body, err := io.ReadAll(e.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var activity pub.Activity
|
||||||
|
activity.UnmarshalJSON(body)
|
||||||
|
|
||||||
|
actor, err := e.App.FindFirstRecordByData("activitypub_actors", "iri", activity.Actor.GetID().String())
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
actor, err = GetActorByIRI(e.App, activity.Actor.GetID().String(), false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verified, err := verifySignature(e.Request, actor.GetString("public_key"))
|
||||||
|
if err != nil || !verified {
|
||||||
|
return e.UnauthorizedError("Invalid http signature", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch activity.Type {
|
||||||
|
case pub.FollowType:
|
||||||
|
ProcessFollowActivity(e.App, actor, activity)
|
||||||
|
case pub.AcceptType:
|
||||||
|
ProcessAcceptActivity(e.App, actor, activity)
|
||||||
|
case pub.UndoType:
|
||||||
|
ProcessUndoActivity(e.App, actor, activity)
|
||||||
|
case pub.UpdateType:
|
||||||
|
fallthrough
|
||||||
|
case pub.CreateType:
|
||||||
|
ProcessCreateOrUpdateActivity(e.App, actor, activity)
|
||||||
|
case pub.DeleteType:
|
||||||
|
ProcessDeleteActivity(e.App, actor, activity)
|
||||||
|
case pub.AnnounceType:
|
||||||
|
ProcessAnnounceActivity(e.App, actor, activity)
|
||||||
|
case pub.LikeType:
|
||||||
|
ProcessLikeActivity(e.App, actor, activity)
|
||||||
|
}
|
||||||
|
return e.JSON(http.StatusOK, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifySignature(req *http.Request, publicKeyPem string) (bool, error) {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return false, fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
block, _ := pem.Decode([]byte(publicKeyPem))
|
||||||
|
if block == nil || block.Type != "PUBLIC KEY" {
|
||||||
|
return false, fmt.Errorf("could not decode publicKeyPem to PUBLIC KEY pem block type")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.URL = &url.URL{
|
||||||
|
Path: req.Header.Get("X-Forwarded-Path"),
|
||||||
|
}
|
||||||
|
|
||||||
|
url, err := url.Parse(origin)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Host", url.Host)
|
||||||
|
req.Host = url.Host
|
||||||
|
|
||||||
|
publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := httpsig.NewVerifier(req)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = v.Verify(publicKey, httpsig.RSA_SHA256)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
284
db/federation/actor.go
Normal file
284
db/federation/actor.go
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
package federation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
pub "github.com/go-ap/activitypub"
|
||||||
|
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WebfingerResponse struct {
|
||||||
|
Subject string `json:"subject"`
|
||||||
|
Links []struct {
|
||||||
|
Rel string `json:"rel"`
|
||||||
|
Href string `json:"href"`
|
||||||
|
} `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func SplitHandle(handle string) (string, string) {
|
||||||
|
|
||||||
|
cleaned := strings.TrimPrefix(handle, "@")
|
||||||
|
cleaned = strings.TrimSpace(cleaned)
|
||||||
|
|
||||||
|
if !strings.Contains(cleaned, "@") {
|
||||||
|
return cleaned, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.SplitN(cleaned, "@", 2)
|
||||||
|
user := parts[0]
|
||||||
|
domain := parts[1]
|
||||||
|
|
||||||
|
return user, domain
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetActorByHandle(app core.App, handle string, includeFollows bool) (*core.Record, error) {
|
||||||
|
username, domain := SplitHandle(handle)
|
||||||
|
|
||||||
|
filter := "username={:username}&&"
|
||||||
|
if domain != "" {
|
||||||
|
filter += "domain={:domain}"
|
||||||
|
} else {
|
||||||
|
filter += "isLocal=true"
|
||||||
|
}
|
||||||
|
|
||||||
|
var dbActor *core.Record
|
||||||
|
dbActor, err := app.FindFirstRecordByFilter("activitypub_actors", filter, dbx.Params{"username": username, "domain": domain})
|
||||||
|
if err != nil && err == sql.ErrNoRows {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_actors")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dbActor = core.NewRecord(collection)
|
||||||
|
dbActor.Set("isLocal", false)
|
||||||
|
iri, err := iriFromHandle(domain, username)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dbActor.Set("iri", iri)
|
||||||
|
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return assembleActor(dbActor, app, includeFollows)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetActorByIRI(app core.App, iri string, includeFollows bool) (*core.Record, error) {
|
||||||
|
var dbActor *core.Record
|
||||||
|
dbActor, err := app.FindFirstRecordByFilter("activitypub_actors", "iri={:iri}", dbx.Params{"iri": iri})
|
||||||
|
if err != nil && err == sql.ErrNoRows {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_actors")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dbActor = core.NewRecord(collection)
|
||||||
|
dbActor.Set("isLocal", false)
|
||||||
|
dbActor.Set("iri", iri)
|
||||||
|
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return assembleActor(dbActor, app, includeFollows)
|
||||||
|
}
|
||||||
|
|
||||||
|
func iriFromHandle(domain string, username string) (string, error) {
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
webfingerURL := fmt.Sprintf("https://%s/.well-known/webfinger?resource=acct:%s@%s", domain, username, domain)
|
||||||
|
resp, err := client.Get(webfingerURL)
|
||||||
|
if err != nil || resp.StatusCode != http.StatusOK {
|
||||||
|
return "", fmt.Errorf("webfinger request failed: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var wf WebfingerResponse
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&wf); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, link := range wf.Links {
|
||||||
|
if link.Rel == "self" {
|
||||||
|
return link.Href, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("no iri in response")
|
||||||
|
}
|
||||||
|
|
||||||
|
func assembleActor(dbActor *core.Record, app core.App, includeFollows bool) (*core.Record, error) {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return nil, fmt.Errorf("ORIGIN environment variable not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if dbActor.GetBool("isLocal") {
|
||||||
|
user, err := app.FindRecordById("users", dbActor.GetString("user"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
settings, err := app.FindFirstRecordByData("settings", "user", user.Id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.GetString("avatar") != "" {
|
||||||
|
dbActor.Set("icon", fmt.Sprintf("%s/api/v1/files/users/%s/%s", origin, user.Id, user.GetString("avatar")))
|
||||||
|
}
|
||||||
|
dbActor.Set("summary", settings.GetString("bio"))
|
||||||
|
followerCount, err := app.CountRecords("follows", dbx.NewExp("followee={:user}", dbx.Params{"user": dbActor.Id}))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dbActor.Set("followerCount", followerCount)
|
||||||
|
followingCount, err := app.CountRecords("follows", dbx.NewExp("follower={:user}", dbx.Params{"user": dbActor.Id}))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dbActor.Set("followingCount", followingCount)
|
||||||
|
|
||||||
|
dbActor.Set("last_fetched", time.Now())
|
||||||
|
|
||||||
|
privacy := settings.GetString("privacy")
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
json.Unmarshal([]byte(privacy), &result)
|
||||||
|
|
||||||
|
private := result["account"] == "private"
|
||||||
|
|
||||||
|
if private {
|
||||||
|
return nil, fmt.Errorf("profile is private")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// check if value is still cached
|
||||||
|
twoHoursAgo := time.Now().Add(-2 * time.Hour)
|
||||||
|
if !includeFollows && dbActor.GetDateTime("last_fetched").Time().After(twoHoursAgo) {
|
||||||
|
return dbActor, nil
|
||||||
|
}
|
||||||
|
pubActor, followers, following, err := fetchRemoteActor(dbActor.GetString("iri"), includeFollows)
|
||||||
|
if err != nil {
|
||||||
|
if dbActor.Id != "" {
|
||||||
|
return dbActor, err
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
icon := ""
|
||||||
|
if pub.IsObject(pubActor.Icon) {
|
||||||
|
iconObject, err := pub.ToObject(pubActor.Icon)
|
||||||
|
if err == nil && iconObject.URL != nil {
|
||||||
|
icon = iconObject.URL.GetID().String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedUrl, err := url.Parse(dbActor.GetString("iri"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
domain := strings.TrimPrefix(parsedUrl.Hostname(), "www.")
|
||||||
|
|
||||||
|
dbActor.Set("domain", domain)
|
||||||
|
dbActor.Set("followers", pubActor.Followers.GetID().String())
|
||||||
|
dbActor.Set("inbox", pubActor.Inbox.GetID().String())
|
||||||
|
dbActor.Set("iri", pubActor.GetID().String())
|
||||||
|
dbActor.Set("username", pubActor.Name.String())
|
||||||
|
dbActor.Set("preferred_username", pubActor.PreferredUsername.String())
|
||||||
|
dbActor.Set("following", pubActor.Following.GetID().String())
|
||||||
|
dbActor.Set("summary", pubActor.Summary.String())
|
||||||
|
dbActor.Set("outbox", pubActor.Outbox.GetID().String())
|
||||||
|
dbActor.Set("icon", icon)
|
||||||
|
dbActor.Set("published", pubActor.Published.String())
|
||||||
|
dbActor.Set("public_key", pubActor.PublicKey.PublicKeyPem)
|
||||||
|
dbActor.Set("last_fetched", time.Now())
|
||||||
|
|
||||||
|
if includeFollows {
|
||||||
|
dbActor.Set("followerCount", int(followers.TotalItems))
|
||||||
|
dbActor.Set("followingCount", int(following.TotalItems))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Save(dbActor)
|
||||||
|
if err != nil && err.Error() == "iri: Value must be unique." {
|
||||||
|
dbActor, err = app.FindFirstRecordByData("activitypub_actors", "iri", dbActor.GetString("iri"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dbActor, nil
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbActor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetches an AP actor and optionally followers/following collections
|
||||||
|
func fetchRemoteActor(iri string, includeFollows bool) (*pub.Actor, *pub.OrderedCollection, *pub.OrderedCollection, error) {
|
||||||
|
client := &http.Client{}
|
||||||
|
headers := map[string]string{
|
||||||
|
"Accept": "application/ld+json",
|
||||||
|
}
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("GET", iri, nil)
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, fmt.Errorf("actor fetch failed: %v", err)
|
||||||
|
} else if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, nil, nil, fmt.Errorf("actor fetch failed: status %v", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var pubActor pub.Actor
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&pubActor); err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var followers, following pub.OrderedCollection
|
||||||
|
|
||||||
|
if includeFollows {
|
||||||
|
// Fetch followers
|
||||||
|
if data, err := fetchCollection(pubActor.Followers.GetID().String(), headers); err == nil {
|
||||||
|
followers = *data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch following
|
||||||
|
if data, err := fetchCollection(pubActor.Following.GetID().String(), headers); err == nil {
|
||||||
|
following = *data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pubActor, &followers, &following, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchCollection(url string, headers map[string]string) (*pub.OrderedCollection, error) {
|
||||||
|
req, _ := http.NewRequest("GET", url, nil)
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil || resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("collection fetch failed for %s: %v", url, err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var collection pub.OrderedCollection
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&collection); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &collection, nil
|
||||||
|
}
|
||||||
276
db/federation/announce.go
Normal file
276
db/federation/announce.go
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
package federation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"pocketbase/util"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
|
||||||
|
pub "github.com/go-ap/activitypub"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AnnounceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TrailAnnounceType AnnounceType = "trail"
|
||||||
|
ListAnnounceType AnnounceType = "list"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateAnnounceActivity(app core.App, record *core.Record, typ AnnounceType) error {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
var subject *core.Record
|
||||||
|
var object pub.Item
|
||||||
|
var err error
|
||||||
|
if typ == TrailAnnounceType {
|
||||||
|
subject, err = app.FindRecordById("trails", record.GetString("trail"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
object, err = util.ObjectFromTrail(app, subject, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if typ == ListAnnounceType {
|
||||||
|
subject, err = app.FindRecordById("lists", record.GetString("list"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
object, err = util.ObjectFromList(app, subject)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("unknown announce type")
|
||||||
|
}
|
||||||
|
|
||||||
|
subjectActor, err := app.FindRecordById("activitypub_actors", subject.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
objectActor, err := app.FindRecordById("activitypub_actors", record.GetString("actor"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
to := objectActor.GetString("iri")
|
||||||
|
actor := subjectActor.GetString("iri")
|
||||||
|
|
||||||
|
activity := pub.AnnounceNew(pub.IRI(id), object)
|
||||||
|
activity.To = pub.ItemCollection{pub.IRI(to)}
|
||||||
|
activity.Actor = pub.IRI(actor)
|
||||||
|
activity.Tag = pub.ItemCollection{
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "permission")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, record.GetString("permission"))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = PostActivity(app, subjectActor, activity, []string{objectActor.GetString("inbox")})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
activityRecord := core.NewRecord(collection)
|
||||||
|
activityRecord.Set("id", recordId)
|
||||||
|
activityRecord.Set("iri", id)
|
||||||
|
activityRecord.Set("to", []string{to})
|
||||||
|
activityRecord.Set("type", string(pub.AnnounceType))
|
||||||
|
activityRecord.Set("object", object)
|
||||||
|
activityRecord.Set("actor", actor)
|
||||||
|
activityRecord.Set("published", time.Now())
|
||||||
|
|
||||||
|
return app.Save(activityRecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
// process incoming announce activity
|
||||||
|
func ProcessAnnounceActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
object := activity.Object.GetID().String()
|
||||||
|
|
||||||
|
if strings.Contains(object, "/api/v1/trail") {
|
||||||
|
processTrailAnnounceActivity(app, actor, activity)
|
||||||
|
|
||||||
|
} else if strings.Contains(object, "/api/v1/list") {
|
||||||
|
processListAnnounceActivity(app, actor, activity)
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("unknown announce type")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func processTrailAnnounceActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
|
||||||
|
objectActor, err := app.FindFirstRecordByData("activitypub_actors", "iri", activity.To[0].GetID().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var trail *core.Record
|
||||||
|
if !actor.GetBool("isLocal") {
|
||||||
|
trail, err = util.TrailFromActivity(activity, app, actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
permission := "view"
|
||||||
|
// tags, err := pub.ToItemCollection(activity.Tag)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for _, tag := range tags.Collection() {
|
||||||
|
// tagObj, err := pub.ToObject(tag)
|
||||||
|
// if err != nil {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// name := tagObj.Name.First().Value.String()
|
||||||
|
// content := tagObj.Content.First().Value.String()
|
||||||
|
// if name == "permission" {
|
||||||
|
// permission = content
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
record, err := app.FindFirstRecordByFilter("trail_share", "trail={:trailId}&&actor={:actorId}", dbx.Params{"trailId": trail.Id, "actorId": objectActor.Id})
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("trail_share")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
record = core.NewRecord(collection)
|
||||||
|
record.Set("trail", trail.Id)
|
||||||
|
record.Set("actor", objectActor.Id)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record.Set("permission", permission)
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
trailUrl, err := url.Parse(activity.Object.GetID().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
trailId := path.Base(trailUrl.Path)
|
||||||
|
trail, err = app.FindRecordById("trails", trailId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := util.Notification{
|
||||||
|
Type: util.TrailShare,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"id": trail.Id,
|
||||||
|
"trail": trail.GetString("name"),
|
||||||
|
"author": fmt.Sprintf("@%s@%s", actor.GetString("username"), actor.GetString("domain")),
|
||||||
|
},
|
||||||
|
Seen: false,
|
||||||
|
Author: actor.Id,
|
||||||
|
}
|
||||||
|
err = util.SendNotification(app, notification, objectActor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processListAnnounceActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
|
||||||
|
objectActor, err := app.FindFirstRecordByData("activitypub_actors", "iri", activity.To[0].GetID().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var list *core.Record
|
||||||
|
if !actor.GetBool("isLocal") {
|
||||||
|
list, err = util.ListFromActivity(activity, app, actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record, err := app.FindFirstRecordByFilter("list_share", "list={:listId}&&actor={:actorId}", dbx.Params{"listId": list.Id, "actorId": objectActor.Id})
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("list_share")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
record = core.NewRecord(collection)
|
||||||
|
record.Set("list", list.Id)
|
||||||
|
record.Set("actor", objectActor.Id)
|
||||||
|
record.Set("permission", "view")
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
listUrl, err := url.Parse(activity.Object.GetID().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
listId := path.Base(listUrl.Path)
|
||||||
|
list, err = app.FindRecordById("trails", listId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notification := util.Notification{
|
||||||
|
Type: util.ListShare,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"id": list.Id,
|
||||||
|
"list": list.GetString("name"),
|
||||||
|
"author": fmt.Sprintf("@%s@%s", actor.GetString("username"), actor.GetString("domain")),
|
||||||
|
},
|
||||||
|
Seen: false,
|
||||||
|
Author: actor.Id,
|
||||||
|
}
|
||||||
|
err = util.SendNotification(app, notification, objectActor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
849
db/federation/create.go
Normal file
849
db/federation/create.go
Normal file
@@ -0,0 +1,849 @@
|
|||||||
|
package federation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"pocketbase/util"
|
||||||
|
|
||||||
|
pub "github.com/go-ap/activitypub"
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/filesystem"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateTrailActivity(app core.App, trail *core.Record, typ pub.ActivityVocabularyType) error {
|
||||||
|
if !trail.GetBool("public") {
|
||||||
|
// only broadcast the trail if it is public
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
trailAuthor, err := app.FindRecordById("activitypub_actors", trail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
to := "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
|
||||||
|
mentionedActors, handles, err := ActorsFromMentions(app, trail.GetString("description"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mentions := []string{}
|
||||||
|
cc := pub.ItemCollection{pub.IRI(trailAuthor.GetString("followers"))}
|
||||||
|
tags := pub.ItemCollection{}
|
||||||
|
for i, m := range mentionedActors {
|
||||||
|
inbox := m.GetString("inbox")
|
||||||
|
mention := pub.MentionNew(pub.IRI(m.GetString("iri")))
|
||||||
|
mention.Href = pub.IRI(m.GetString("iri"))
|
||||||
|
mention.Name = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, handles[i]))
|
||||||
|
tags.Append(mention)
|
||||||
|
|
||||||
|
mentions = append(mentions, inbox)
|
||||||
|
cc.Append(pub.IRI(inbox))
|
||||||
|
}
|
||||||
|
|
||||||
|
trailObject, err := util.ObjectFromTrail(app, trail, &tags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
activity := pub.ActivityNew(pub.IRI(id), typ, trailObject)
|
||||||
|
activity.Actor = pub.IRI(trailAuthor.GetString("iri"))
|
||||||
|
activity.To = pub.ItemCollection{pub.IRI(to)}
|
||||||
|
activity.CC = cc
|
||||||
|
activity.Published = time.Now()
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("to", []string{to})
|
||||||
|
record.Set("cc", cc)
|
||||||
|
record.Set("type", string(typ))
|
||||||
|
record.Set("object", trailObject)
|
||||||
|
record.Set("actor", trailAuthor.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": trailAuthor.Id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recipients := mentions
|
||||||
|
for _, f := range follows {
|
||||||
|
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recipients = append(recipients, follower.GetString("inbox"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return PostActivity(app, trailAuthor, activity, recipients)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateCommentActivity(app core.App, comment *core.Record, typ pub.ActivityVocabularyType) error {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// author of the comment
|
||||||
|
commentAuthor, err := app.FindRecordById("activitypub_actors", comment.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
commentTrail, err := app.FindRecordById("trails", comment.GetString("trail"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
commentTrailAuthor, err := app.FindRecordById("activitypub_actors", commentTrail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
activityRecordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, activityRecordId)
|
||||||
|
to := "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
|
||||||
|
mentionedActors, handles, err := ActorsFromMentions(app, comment.GetString("text"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recipients := []string{}
|
||||||
|
tags := pub.ItemCollection{}
|
||||||
|
for i, m := range mentionedActors {
|
||||||
|
mention := pub.MentionNew(pub.IRI(m.GetString("iri")))
|
||||||
|
mention.Href = pub.IRI(m.GetString("iri"))
|
||||||
|
mention.Name = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, handles[i]))
|
||||||
|
tags.Append(mention)
|
||||||
|
|
||||||
|
recipients = append(recipients, m.GetString("inbox"))
|
||||||
|
}
|
||||||
|
recipients = append(recipients, commentTrailAuthor.GetString("inbox"))
|
||||||
|
|
||||||
|
cc := pub.ItemCollection{}
|
||||||
|
for _, r := range recipients {
|
||||||
|
cc.Append(pub.IRI(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
author := commentAuthor.GetString("iri")
|
||||||
|
|
||||||
|
commentObject, err := util.ObjectFromComment(app, comment, &tags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
activity := pub.ActivityNew(pub.IRI(id), typ, commentObject)
|
||||||
|
activity.Actor = pub.IRI(author)
|
||||||
|
activity.To = pub.ItemCollection{pub.IRI(to)}
|
||||||
|
activity.CC = cc
|
||||||
|
activity.Published = time.Now()
|
||||||
|
activity.Object = commentObject
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", activityRecordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("to", []string{to})
|
||||||
|
record.Set("cc", recipients)
|
||||||
|
record.Set("type", string(typ))
|
||||||
|
record.Set("object", commentObject)
|
||||||
|
record.Set("actor", author)
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return PostActivity(app, commentAuthor, activity, recipients)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateSummitLogActivity(app core.App, summitLog *core.Record, typ pub.ActivityVocabularyType) error {
|
||||||
|
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
summitLogAuthor, err := app.FindRecordById("activitypub_actors", summitLog.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var summitLogAuthorId string
|
||||||
|
// first check if we find the trail locally
|
||||||
|
summitLogTrail, err := app.FindRecordById("trails", summitLog.GetString("trail"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !summitLogTrail.GetBool("public") {
|
||||||
|
// only broadcast the log if the trail it belongs to is public
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
summitLogAuthorId = summitLogTrail.GetString("author")
|
||||||
|
|
||||||
|
summitLogTrailAuthor, err := app.FindRecordById("activitypub_actors", summitLogAuthorId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var trailIRI pub.IRI
|
||||||
|
if summitLogTrailAuthor.GetBool("isLocal") {
|
||||||
|
trailId := summitLog.GetString("trail")
|
||||||
|
trailIRI = pub.IRI(fmt.Sprintf("%s/api/v1/trail/%s", origin, trailId))
|
||||||
|
} else {
|
||||||
|
trailIRI = pub.IRI(summitLogTrail.GetString("iri"))
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
to := pub.ItemCollection{pub.IRI("https://www.w3.org/ns/activitystreams#Public")}
|
||||||
|
|
||||||
|
// someone else created the summit log on the trail -> inform the trail's author
|
||||||
|
if summitLogAuthor.Id != summitLogTrailAuthor.Id {
|
||||||
|
to.Append(pub.IRI(summitLogTrailAuthor.GetString("iri")))
|
||||||
|
}
|
||||||
|
|
||||||
|
mentionedActors, handles, err := ActorsFromMentions(app, summitLog.GetString("text"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mentions := []string{}
|
||||||
|
cc := pub.ItemCollection{pub.IRI(summitLogAuthor.GetString("followers"))}
|
||||||
|
mentionTags := pub.ItemCollection{}
|
||||||
|
for i, m := range mentionedActors {
|
||||||
|
inbox := m.GetString("inbox")
|
||||||
|
mention := pub.MentionNew(pub.IRI(m.GetString("iri")))
|
||||||
|
mention.Href = pub.IRI(m.GetString("iri"))
|
||||||
|
mention.Name = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, handles[i]))
|
||||||
|
mentionTags.Append(mention)
|
||||||
|
|
||||||
|
mentions = append(mentions, inbox)
|
||||||
|
cc.Append(pub.IRI(inbox))
|
||||||
|
}
|
||||||
|
|
||||||
|
photos := summitLog.GetStringSlice("photos")
|
||||||
|
|
||||||
|
gpx := ""
|
||||||
|
if summitLog.GetString("gpx") != "" {
|
||||||
|
gpx = fmt.Sprintf("%s/api/v1/files/summit_logs/%s/%s", origin, summitLog.Id, summitLog.GetString("gpx"))
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments := make(pub.ItemCollection, max(len(photos), 2))
|
||||||
|
for i := range len(photos) {
|
||||||
|
iri := fmt.Sprintf("%s/api/v1/files/summit_logs/%s/%s", origin, summitLog.Id, photos[i])
|
||||||
|
|
||||||
|
attachments[i] = pub.Document{
|
||||||
|
Type: pub.ImageType,
|
||||||
|
MediaType: "image/jpeg",
|
||||||
|
URL: pub.IRI(iri),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if gpx != "" {
|
||||||
|
attachments.Append(pub.Document{
|
||||||
|
Type: pub.DocumentType,
|
||||||
|
MediaType: "application/xml+gpx",
|
||||||
|
URL: pub.IRI(gpx),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
tags := pub.ItemCollection{
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "elevation_gain")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, fmt.Sprintf("%fm", summitLog.GetFloat("elevation_gain")))),
|
||||||
|
},
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "elevation_loss")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, fmt.Sprintf("%fm", summitLog.GetFloat("elevation_loss")))),
|
||||||
|
},
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "distance")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, fmt.Sprintf("%fm", summitLog.GetFloat("distance")))),
|
||||||
|
},
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "duration")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, fmt.Sprintf("%fm", summitLog.GetFloat("duration")))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range mentionTags {
|
||||||
|
tags.Append(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
logObject := pub.ObjectNew(pub.NoteType)
|
||||||
|
|
||||||
|
logObject.Content = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, summitLog.GetString("text")))
|
||||||
|
logObject.AttributedTo = pub.IRI(summitLogAuthor.GetString("iri"))
|
||||||
|
logObject.Published = summitLog.GetDateTime("created").Time()
|
||||||
|
logObject.ID = pub.IRI(fmt.Sprintf("%s/api/v1/summit-log/%s", origin, summitLog.Id))
|
||||||
|
logObject.URL = pub.IRI(fmt.Sprintf("%s/trail/view/@%s/%s", origin, summitLogTrailAuthor.GetString("username"), summitLog.GetString("trail")))
|
||||||
|
logObject.InReplyTo = trailIRI
|
||||||
|
logObject.Tag = tags
|
||||||
|
|
||||||
|
logObject.StartTime = summitLog.GetDateTime("date").Time()
|
||||||
|
logObject.Attachment = attachments
|
||||||
|
|
||||||
|
activity := pub.ActivityNew(pub.IRI(id), typ, logObject)
|
||||||
|
activity.Actor = pub.IRI(summitLogAuthor.GetString("iri"))
|
||||||
|
activity.To = to
|
||||||
|
activity.CC = cc
|
||||||
|
activity.Published = time.Now()
|
||||||
|
|
||||||
|
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": summitLogAuthor.Id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recipients := mentions
|
||||||
|
|
||||||
|
for _, f := range follows {
|
||||||
|
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recipients = append(recipients, follower.GetString("inbox"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if summitLogAuthor.Id != summitLogTrailAuthor.Id {
|
||||||
|
recipients = append(recipients, summitLogTrailAuthor.GetString("inbox"))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = PostActivity(app, summitLogAuthor, activity, recipients)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("to", to)
|
||||||
|
record.Set("cc", cc)
|
||||||
|
record.Set("type", string(typ))
|
||||||
|
record.Set("object", logObject)
|
||||||
|
record.Set("actor", summitLogAuthor.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
return app.Save(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateListActivity(app core.App, list *core.Record, typ pub.ActivityVocabularyType) error {
|
||||||
|
if !list.GetBool("public") {
|
||||||
|
// only broadcast the list if it is public
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// author of the list
|
||||||
|
listAuthor, err := app.FindRecordById("activitypub_actors", list.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
activityRecordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, activityRecordId)
|
||||||
|
to := "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
cc := listAuthor.GetString("followers")
|
||||||
|
author := listAuthor.GetString("iri")
|
||||||
|
|
||||||
|
listObject, err := util.ObjectFromList(app, list)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
activity := pub.ActivityNew(pub.IRI(id), typ, listObject)
|
||||||
|
activity.Actor = pub.IRI(author)
|
||||||
|
activity.To = pub.ItemCollection{pub.IRI(to)}
|
||||||
|
activity.CC = pub.ItemCollection{pub.IRI(cc)}
|
||||||
|
activity.Published = time.Now()
|
||||||
|
activity.Object = listObject
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": listAuthor.Id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recipients := []string{}
|
||||||
|
for _, f := range follows {
|
||||||
|
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recipients = append(recipients, follower.GetString("inbox"))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = PostActivity(app, listAuthor, activity, recipients)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", activityRecordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("to", []string{to})
|
||||||
|
record.Set("cc", []string{cc})
|
||||||
|
record.Set("type", string(typ))
|
||||||
|
record.Set("object", listObject)
|
||||||
|
record.Set("actor", author)
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
return app.Save(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProcessCreateOrUpdateActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if strings.Contains(activity.Object.GetID().String(), "/api/v1/trail") {
|
||||||
|
err = processCreateOrUpdateTrailActivity(activity, app, actor)
|
||||||
|
} else if strings.Contains(activity.Object.GetID().String(), "/api/v1/summit-log") {
|
||||||
|
err = processCreateOrUpdateSummitLogActivity(activity, app, actor)
|
||||||
|
} else if strings.Contains(activity.Object.GetID().String(), "/api/v1/list") {
|
||||||
|
err = processCreateOrUpdateListActivity(activity, app, actor)
|
||||||
|
} else {
|
||||||
|
err = processCreateOrUpdateCommentActivity(activity, app, actor)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func processCreateOrUpdateTrailActivity(activity pub.Activity, app core.App, actor *core.Record) error {
|
||||||
|
|
||||||
|
// no need to do anything if the actor is local
|
||||||
|
if actor.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
trail, err := util.TrailFromActivity(activity, app, actor)
|
||||||
|
|
||||||
|
trailObject, _ := pub.ToObject(activity.Object)
|
||||||
|
|
||||||
|
for _, t := range trailObject.Tag {
|
||||||
|
if t.GetType() == pub.MentionType {
|
||||||
|
mention := t.(*pub.Mention)
|
||||||
|
mentionedActor, err := app.FindFirstRecordByData("activitypub_actors", "iri", mention.Href.GetID().String())
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
notification := util.Notification{
|
||||||
|
Type: util.TrailMention,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"id": trail.Id,
|
||||||
|
"author": fmt.Sprintf("@%s@%s", actor.GetString("username"), actor.GetString("domain")),
|
||||||
|
},
|
||||||
|
Seen: false,
|
||||||
|
Author: actor.Id,
|
||||||
|
}
|
||||||
|
return util.SendNotification(app, notification, mentionedActor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func processCreateOrUpdateCommentActivity(activity pub.Activity, app core.App, actor *core.Record) error {
|
||||||
|
|
||||||
|
commentObject, err := pub.ToObject(activity.Object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if commentObject.InReplyTo == nil {
|
||||||
|
return fmt.Errorf("error processing comment: InReplyTo empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
trailUrl, err := url.Parse(commentObject.InReplyTo.GetLink().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
trailId := path.Base(trailUrl.Path)
|
||||||
|
|
||||||
|
var trail *core.Record
|
||||||
|
trail, err = app.FindFirstRecordByFilter("trails", "iri={:iri} || id={:id}", dbx.Params{"id": trailId, "iri": commentObject.InReplyTo.GetID().String()})
|
||||||
|
|
||||||
|
// if the trail is not present on this instance fetch it
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
trailObject, err := util.TrailObjectFromIRI(commentObject.InReplyTo.GetLink().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
activity := pub.ActivityNew(pub.IRI("new"), pub.CreateType, trailObject)
|
||||||
|
trail, err = util.TrailFromActivity(*activity, app, actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trailAuthor, err := app.FindRecordById("activitypub_actors", trail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need to do anything else if the actor is local
|
||||||
|
if actor.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
record, err := app.FindFirstRecordByData("comments", "iri", commentObject.ID.String())
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("comments")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record = core.NewRecord(collection)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record.Set("iri", commentObject.ID.String())
|
||||||
|
record.Set("text", commentObject.Content.First().Value)
|
||||||
|
record.Set("author", actor.Id)
|
||||||
|
record.Set("trail", trail.Id)
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// send notifications to all mentioned actors
|
||||||
|
for _, t := range commentObject.Tag {
|
||||||
|
if t.GetType() == pub.MentionType {
|
||||||
|
mention := t.(*pub.Mention)
|
||||||
|
mentionedActor, err := app.FindFirstRecordByData("activitypub_actors", "iri", mention.Href.GetID().String())
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
notification := util.Notification{
|
||||||
|
Type: util.CommentMention,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"comment": commentObject.Content.First().Value.String(),
|
||||||
|
"trail_id": trail.Id,
|
||||||
|
"trail_name": trail.GetString("name"),
|
||||||
|
"trail_author": fmt.Sprintf("@%s@%s", trailAuthor.GetString("username"), trailAuthor.GetString("domain")),
|
||||||
|
},
|
||||||
|
Seen: false,
|
||||||
|
Author: actor.Id,
|
||||||
|
}
|
||||||
|
return util.SendNotification(app, notification, mentionedActor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if activity.Type == pub.CreateType {
|
||||||
|
// send a notification to the trail author
|
||||||
|
notification := util.Notification{
|
||||||
|
Type: util.TrailComment,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"comment": commentObject.Content.First().Value.String(),
|
||||||
|
"trail_id": trail.Id,
|
||||||
|
"trail_name": trail.GetString("name"),
|
||||||
|
"trail_author": fmt.Sprintf("@%s@%s", trailAuthor.GetString("username"), trailAuthor.GetString("domain")),
|
||||||
|
},
|
||||||
|
Seen: false,
|
||||||
|
Author: actor.Id,
|
||||||
|
}
|
||||||
|
return util.SendNotification(app, notification, trailAuthor)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processCreateOrUpdateSummitLogActivity(activity pub.Activity, app core.App, actor *core.Record) error {
|
||||||
|
logObject, err := pub.ToObject(activity.Object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
trailIRI, err := url.Parse(logObject.InReplyTo.GetID().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
trailId := path.Base(trailIRI.Path)
|
||||||
|
|
||||||
|
trail, err := app.FindFirstRecordByFilter("trails", "iri={:iri} || id={:id}", dbx.Params{"id": trailId, "iri": logObject.InReplyTo.GetID().String()})
|
||||||
|
// if the trail is not present on this instance fetch it
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
trailObject, err := util.TrailObjectFromIRI(logObject.InReplyTo.GetLink().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
activity := pub.ActivityNew(pub.IRI("new"), pub.CreateType, trailObject)
|
||||||
|
trail, err = util.TrailFromActivity(*activity, app, actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trailAuthor, err := app.FindRecordById("activitypub_actors", trail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newSummitLog := false
|
||||||
|
record, err := app.FindFirstRecordByData("summit_logs", "iri", logObject.ID.String())
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("summit_logs")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record = core.NewRecord(collection)
|
||||||
|
newSummitLog = true
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no need to do anything else if the actor is local
|
||||||
|
if actor.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var distance, duration, elevation_gain, elevation_loss float64
|
||||||
|
tags, err := pub.ToItemCollection(logObject.Tag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tag := range tags.Collection() {
|
||||||
|
tagObj, err := pub.ToObject(tag)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
content := tagObj.Content.First().Value.String()
|
||||||
|
switch tagObj.Name.First().Value.String() {
|
||||||
|
case "elevation_gain":
|
||||||
|
elevation_gain, err = strconv.ParseFloat(content[:len(content)-1], 64)
|
||||||
|
case "elevation_loss":
|
||||||
|
elevation_loss, err = strconv.ParseFloat(content[:len(content)-1], 64)
|
||||||
|
case "duration":
|
||||||
|
duration, err = strconv.ParseFloat(content[:len(content)-1], 64)
|
||||||
|
case "distance":
|
||||||
|
distance, err = strconv.ParseFloat(content[:len(content)-1], 64)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record.Set("date", logObject.StartTime)
|
||||||
|
record.Set("text", logObject.Content.First().Value)
|
||||||
|
record.Set("distance", distance)
|
||||||
|
record.Set("duration", duration)
|
||||||
|
record.Set("elevation_gain", elevation_gain)
|
||||||
|
record.Set("elevation_loss", elevation_loss)
|
||||||
|
record.Set("author", actor.Id)
|
||||||
|
record.Set("trail", trail.Id)
|
||||||
|
record.Set("iri", logObject.ID.String())
|
||||||
|
|
||||||
|
if logObject.Attachment != nil {
|
||||||
|
attachments, err := pub.ToItemCollection(logObject.Attachment)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
photoURLs := []string{}
|
||||||
|
gpxURL := ""
|
||||||
|
for _, a := range attachments.Collection() {
|
||||||
|
attachment, err := pub.ToObject(a)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if attachment.Type == pub.DocumentType && attachment.MediaType == "application/xml+gpx" {
|
||||||
|
gpxURL = attachment.URL.GetLink().String()
|
||||||
|
} else if attachment.Type == pub.ImageType {
|
||||||
|
photoURLs = append(photoURLs, attachment.URL.GetLink().String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(photoURLs) > 0 {
|
||||||
|
photos := make([]*filesystem.File, len(photoURLs))
|
||||||
|
for i, purl := range photoURLs {
|
||||||
|
photo, err := filesystem.NewFileFromURL(context.Background(), purl)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
photos[i] = photo
|
||||||
|
}
|
||||||
|
|
||||||
|
record.Set("photos", photos)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gpxURL != "" {
|
||||||
|
gpx, err := filesystem.NewFileFromURL(context.Background(), gpxURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record.Set("gpx", gpx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// send notifications to all mentioned actors
|
||||||
|
for _, t := range logObject.Tag {
|
||||||
|
if t.GetType() == pub.MentionType {
|
||||||
|
mention := t.(*pub.Mention)
|
||||||
|
mentionedActor, err := app.FindFirstRecordByData("activitypub_actors", "iri", mention.Href.GetID().String())
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
notification := util.Notification{
|
||||||
|
Type: util.SummitLogMention,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"trail_id": trail.Id,
|
||||||
|
"trail_name": trail.GetString("name"),
|
||||||
|
"trail_author": fmt.Sprintf("@%s@%s", trailAuthor.GetString("username"), trailAuthor.GetString("domain")),
|
||||||
|
},
|
||||||
|
Seen: false,
|
||||||
|
Author: actor.Id,
|
||||||
|
}
|
||||||
|
return util.SendNotification(app, notification, mentionedActor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if newSummitLog {
|
||||||
|
// send a notification to the trail author
|
||||||
|
notification := util.Notification{
|
||||||
|
Type: util.SummitLogCreate,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"trail_id": trail.Id,
|
||||||
|
"trail_name": trail.GetString("name"),
|
||||||
|
"trail_author": fmt.Sprintf("@%s@%s", trailAuthor.GetString("username"), trailAuthor.GetString("domain")),
|
||||||
|
},
|
||||||
|
Seen: false,
|
||||||
|
Author: actor.Id,
|
||||||
|
}
|
||||||
|
return util.SendNotification(app, notification, trailAuthor)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processCreateOrUpdateListActivity(activity pub.Activity, app core.App, actor *core.Record) error {
|
||||||
|
|
||||||
|
// no need to do anything if the actor is local
|
||||||
|
if actor.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := util.ListFromActivity(activity, app, actor)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActorsFromMentions(app core.App, htmlStr string) ([]*core.Record, []string, error) {
|
||||||
|
doc, err := html.Parse(strings.NewReader(htmlStr))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var handles []string
|
||||||
|
var actors []*core.Record
|
||||||
|
|
||||||
|
var f func(*html.Node)
|
||||||
|
f = func(n *html.Node) {
|
||||||
|
if n.Type == html.ElementNode && n.Data == "a" {
|
||||||
|
var isMention bool
|
||||||
|
for _, attr := range n.Attr {
|
||||||
|
if attr.Key == "class" && strings.Contains(attr.Val, "mention") {
|
||||||
|
isMention = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isMention && n.FirstChild != nil && n.FirstChild.Type == html.TextNode {
|
||||||
|
handle := strings.TrimSpace(n.FirstChild.Data)
|
||||||
|
if strings.HasPrefix(handle, "@") {
|
||||||
|
handles = append(handles, handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||||
|
f(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f(doc)
|
||||||
|
|
||||||
|
for _, h := range handles {
|
||||||
|
actor, err := GetActorByHandle(app, h, false)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
actors = append(actors, actor)
|
||||||
|
}
|
||||||
|
|
||||||
|
return actors, handles, nil
|
||||||
|
}
|
||||||
377
db/federation/delete.go
Normal file
377
db/federation/delete.go
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
package federation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
pub "github.com/go-ap/activitypub"
|
||||||
|
"github.com/meilisearch/meilisearch-go"
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateTrailDeleteActivity(app core.App, r *core.Record) error {
|
||||||
|
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
author, err := app.FindRecordById("activitypub_actors", r.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
to := "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
cc := author.GetString("iri") + "/followers"
|
||||||
|
object := fmt.Sprintf("%s/api/v1/trail/%s", origin, r.Id)
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("type", string(pub.DeleteType))
|
||||||
|
record.Set("to", to)
|
||||||
|
record.Set("cc", cc)
|
||||||
|
record.Set("object", object)
|
||||||
|
record.Set("actor", author.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
|
||||||
|
activity.Actor = pub.IRI(author.GetString("iri"))
|
||||||
|
activity.To = pub.ItemCollection{pub.IRI(to)}
|
||||||
|
activity.CC = pub.ItemCollection{pub.IRI(cc)}
|
||||||
|
activity.Published = time.Now()
|
||||||
|
|
||||||
|
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": author.Id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recipients := []string{}
|
||||||
|
for _, f := range follows {
|
||||||
|
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recipients = append(recipients, follower.GetString("inbox"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return PostActivity(app, author, activity, recipients)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateCommentDeleteActivity(app core.App, client meilisearch.ServiceManager, r *core.Record) error {
|
||||||
|
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
author, err := app.FindRecordById("activitypub_actors", r.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !author.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
commentTrail, err := app.FindRecordById("trails", r.GetString("trail"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
commentTrailAuthor, err := app.FindRecordById("activitypub_actors", commentTrail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if commentTrailAuthor.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
to := commentTrailAuthor.GetString("iri")
|
||||||
|
object := fmt.Sprintf("%s/api/v1/comment/%s", origin, r.Id)
|
||||||
|
|
||||||
|
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
|
||||||
|
activity.Actor = pub.IRI(author.GetString("iri"))
|
||||||
|
activity.To = pub.ItemCollection{pub.IRI(to)}
|
||||||
|
activity.Published = time.Now()
|
||||||
|
|
||||||
|
err = PostActivity(app, author, activity, []string{to + "/inbox"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("type", string(pub.DeleteType))
|
||||||
|
record.Set("to", to)
|
||||||
|
record.Set("object", object)
|
||||||
|
record.Set("actor", author.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
return app.Save(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateSummitLogDeleteActivity(app core.App, r *core.Record) error {
|
||||||
|
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
author, err := app.FindRecordById("activitypub_actors", r.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !author.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
summitLogTrail, err := app.FindRecordById("trails", r.GetString("trail"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
summitLogTrailAuthor, err := app.FindRecordById("activitypub_actors", summitLogTrail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
to := summitLogTrailAuthor.GetString("iri")
|
||||||
|
object := fmt.Sprintf("%s/api/v1/summit-log/%s", origin, r.Id)
|
||||||
|
cc := pub.ItemCollection{pub.IRI(author.GetString("iri") + "/followers")}
|
||||||
|
|
||||||
|
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
|
||||||
|
activity.Actor = pub.IRI(author.GetString("iri"))
|
||||||
|
activity.To = pub.ItemCollection{pub.IRI(to)}
|
||||||
|
activity.CC = cc
|
||||||
|
activity.Published = time.Now()
|
||||||
|
|
||||||
|
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": author.Id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recipients := []string{}
|
||||||
|
|
||||||
|
for _, f := range follows {
|
||||||
|
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recipients = append(recipients, follower.GetString("inbox"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if author.Id != summitLogTrailAuthor.Id {
|
||||||
|
recipients = append(recipients, summitLogTrailAuthor.GetString("inbox"))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = PostActivity(app, author, activity, recipients)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("type", string(pub.DeleteType))
|
||||||
|
record.Set("to", to)
|
||||||
|
record.Set("cc", cc)
|
||||||
|
record.Set("object", object)
|
||||||
|
record.Set("actor", author.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
return app.Save(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateListDeleteActivity(app core.App, r *core.Record) error {
|
||||||
|
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
author, err := app.FindRecordById("activitypub_actors", r.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !author.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
to := "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
cc := author.GetString("iri") + "/followers"
|
||||||
|
object := fmt.Sprintf("%s/api/v1/list/%s", origin, r.Id)
|
||||||
|
|
||||||
|
activity := pub.DeleteNew(pub.IRI(id), pub.IRI(object))
|
||||||
|
activity.Actor = pub.IRI(author.GetString("iri"))
|
||||||
|
activity.To = pub.ItemCollection{pub.IRI(to)}
|
||||||
|
activity.CC = pub.ItemCollection{pub.IRI(cc)}
|
||||||
|
activity.Published = time.Now()
|
||||||
|
|
||||||
|
follows, err := app.FindRecordsByFilter("follows", "followee={:followee}&&status='accepted'", "", -1, 0, dbx.Params{"followee": author.Id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recipients := []string{}
|
||||||
|
for _, f := range follows {
|
||||||
|
follower, err := app.FindRecordById("activitypub_actors", f.GetString("follower"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recipients = append(recipients, follower.GetString("inbox"))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = PostActivity(app, author, activity, recipients)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("type", string(pub.DeleteType))
|
||||||
|
record.Set("to", to)
|
||||||
|
record.Set("cc", cc)
|
||||||
|
record.Set("object", object)
|
||||||
|
record.Set("actor", author.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
return app.Save(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProcessDeleteActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
// no need to do anything if the actor is local
|
||||||
|
if actor.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
object := activity.Object.GetID().String()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
switch {
|
||||||
|
case strings.Contains(object, "trail"):
|
||||||
|
err = processDeleteTrailActivity(app, activity)
|
||||||
|
case strings.Contains(object, "comment"):
|
||||||
|
err = processDeleteCommentActivity(app, actor, activity)
|
||||||
|
case strings.Contains(object, "summit-log"):
|
||||||
|
err = processDeleteSummitLogActivity(app, actor, activity)
|
||||||
|
case strings.Contains(object, "list"):
|
||||||
|
err = processDeleteListActivity(app, actor, activity)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processDeleteTrailActivity(app core.App, activity pub.Activity) error {
|
||||||
|
|
||||||
|
trailUrl, err := url.Parse(activity.Object.GetID().String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recordId := path.Base(trailUrl.Path)
|
||||||
|
|
||||||
|
trail, err := app.FindRecordById("trails", recordId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return app.Delete(trail)
|
||||||
|
}
|
||||||
|
|
||||||
|
func processDeleteCommentActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
object := activity.Object.GetID().String()
|
||||||
|
|
||||||
|
comment, err := app.FindFirstRecordByData("comments", "iri", object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if comment.GetString("author") != actor.Id {
|
||||||
|
return fmt.Errorf("actor is not comment author")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = app.Delete(comment)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processDeleteSummitLogActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
object := activity.Object.GetID().String()
|
||||||
|
|
||||||
|
summitLog, err := app.FindFirstRecordByData("summit_logs", "iri", object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if summitLog.GetString("author") != actor.Id {
|
||||||
|
return fmt.Errorf("actor is not summit log author")
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Delete(summitLog)
|
||||||
|
}
|
||||||
|
|
||||||
|
func processDeleteListActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
|
||||||
|
object := activity.Object.GetID().String()
|
||||||
|
list, err := app.FindFirstRecordByData("lists", "iri", object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if list.GetString("author") != actor.Id {
|
||||||
|
return fmt.Errorf("actor is not summit log author")
|
||||||
|
}
|
||||||
|
return app.Delete(list)
|
||||||
|
}
|
||||||
160
db/federation/follow.go
Normal file
160
db/federation/follow.go
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
package federation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"pocketbase/util"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
pub "github.com/go-ap/activitypub"
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
)
|
||||||
|
|
||||||
|
// create outgoing follow activity
|
||||||
|
func CreateFollowActivity(app core.App, follow *core.Record) error {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
follower := follow.GetString("follower")
|
||||||
|
followee := follow.GetString("followee")
|
||||||
|
|
||||||
|
followerActor, err := app.FindRecordById("activitypub_actors", follower)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
followeeActor, err := app.FindRecordById("activitypub_actors", followee)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
|
||||||
|
activity := pub.FollowNew(pub.IRI(id), pub.IRI(followeeActor.GetString("iri")))
|
||||||
|
activity.Actor = pub.IRI(followerActor.GetString("iri"))
|
||||||
|
|
||||||
|
err = PostActivity(app, followerActor, activity, []string{followeeActor.GetString("inbox")})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("type", string(pub.FollowType))
|
||||||
|
record.Set("object", followeeActor.GetString("iri"))
|
||||||
|
record.Set("actor", followerActor.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
return app.Save(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
// process incoming follow activity
|
||||||
|
func ProcessFollowActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the followee in our db
|
||||||
|
object, err := app.FindFirstRecordByData("activitypub_actors", "iri", activity.Object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// a remote actor has requested the follow
|
||||||
|
// this means we have not yet created a follow entry in our db
|
||||||
|
// we accept it immediately
|
||||||
|
if !actor.GetBool("isLocal") {
|
||||||
|
followCollection, err := app.FindCollectionByNameOrId("follows")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
followRecord := core.NewRecord(followCollection)
|
||||||
|
followRecord.Set("follower", actor.Id)
|
||||||
|
followRecord.Set("followee", object.Id)
|
||||||
|
followRecord.Set("status", "accepted")
|
||||||
|
err = app.Save(followRecord)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
|
||||||
|
// send the accept activity back to the actor's inbox
|
||||||
|
acceptActivity := pub.AcceptNew(pub.IRI(id), activity)
|
||||||
|
acceptActivity.Actor = activity.Object
|
||||||
|
err = PostActivity(app, object, acceptActivity, []string{actor.GetString("inbox")})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create record of the accept activity in our db
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("type", string(pub.AcceptType))
|
||||||
|
record.Set("object", activity)
|
||||||
|
record.Set("actor", object.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// send a notification to the followee
|
||||||
|
notification := util.Notification{
|
||||||
|
Type: util.NewFollower,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"follower": fmt.Sprintf("@%s@%s", actor.GetString("username"), actor.GetString("domain")),
|
||||||
|
},
|
||||||
|
Seen: false,
|
||||||
|
Author: actor.Id,
|
||||||
|
}
|
||||||
|
return util.SendNotification(app, notification, object)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProcessAcceptActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
|
||||||
|
followActivity := activity.Object.(*pub.Activity)
|
||||||
|
|
||||||
|
follower, err := app.FindFirstRecordByData("activitypub_actors", "iri", followActivity.Actor)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
follow, err := app.FindFirstRecordByFilter("follows", "follower={:follower} && followee={:followee}", dbx.Params{"follower": follower.Id, "followee": actor.Id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
follow.Set("status", "accepted")
|
||||||
|
err = app.Save(follow)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// err = util.SyncOutbox(app, actor)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
return nil
|
||||||
|
}
|
||||||
118
db/federation/like.go
Normal file
118
db/federation/like.go
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package federation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"pocketbase/util"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
pub "github.com/go-ap/activitypub"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
)
|
||||||
|
|
||||||
|
// create outgoing follow activity
|
||||||
|
func CreateLikeActivity(app core.App, like *core.Record) error {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
actor, err := app.FindRecordById("activitypub_actors", like.GetString("actor"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
trail, err := app.FindRecordById("trails", like.GetString("trail"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
trailAuthor, err := app.FindRecordById("activitypub_actors", trail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
object := trail.GetString("iri")
|
||||||
|
|
||||||
|
if object == "" {
|
||||||
|
// trail is local
|
||||||
|
object = fmt.Sprintf("%s/api/v1/trail/%s", origin, trail.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
|
||||||
|
activity := pub.LikeNew(pub.IRI(id), pub.IRI(object))
|
||||||
|
activity.Actor = pub.IRI(actor.GetString("iri"))
|
||||||
|
|
||||||
|
err = PostActivity(app, actor, activity, []string{trailAuthor.GetString("inbox")})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("type", string(pub.LikeType))
|
||||||
|
record.Set("object", object)
|
||||||
|
record.Set("actor", actor.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
return app.Save(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
// process incoming like activity
|
||||||
|
func ProcessLikeActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
trailId := path.Base(activity.Object.GetID().String())
|
||||||
|
trail, err := app.FindRecordById("trails", trailId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
trailAuthor, err := app.FindRecordById("activitypub_actors", trail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !actor.GetBool("isLocal") {
|
||||||
|
trailLikeCollection, err := app.FindCollectionByNameOrId("trail_like")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
likeRecord := core.NewRecord(trailLikeCollection)
|
||||||
|
likeRecord.Set("trail", trail.Id)
|
||||||
|
likeRecord.Set("actor", actor.Id)
|
||||||
|
err = app.Save(likeRecord)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a notification to the trail author
|
||||||
|
notification := util.Notification{
|
||||||
|
Type: util.TrailLike,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"trail_id": trail.Id,
|
||||||
|
"trail_name": trail.GetString("name"),
|
||||||
|
"trail_author": fmt.Sprintf("@%s", trailAuthor.GetString("username")),
|
||||||
|
"liker": fmt.Sprintf("@%s@%s", actor.GetString("username"), actor.GetString("domain")),
|
||||||
|
},
|
||||||
|
Seen: false,
|
||||||
|
Author: actor.Id,
|
||||||
|
}
|
||||||
|
return util.SendNotification(app, notification, trailAuthor)
|
||||||
|
|
||||||
|
}
|
||||||
194
db/federation/undo.go
Normal file
194
db/federation/undo.go
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
package federation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
pub "github.com/go-ap/activitypub"
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
)
|
||||||
|
|
||||||
|
// create outgoing follow activity
|
||||||
|
func CreateUnfollowActivity(app core.App, follow *core.Record) error {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
follower := follow.GetString("follower")
|
||||||
|
followee := follow.GetString("followee")
|
||||||
|
|
||||||
|
followerActor, err := app.FindRecordById("activitypub_actors", follower)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
followeeActor, err := app.FindRecordById("activitypub_actors", followee)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the original follow activity
|
||||||
|
followActivityRecord, err := app.FindFirstRecordByFilter("activitypub_activities", "actor={:actor}&&object={:object}&&type={:type}", dbx.Params{"actor": followerActor.GetString("iri"), "object": followeeActor.GetString("iri"), "type": string(pub.FollowType)})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
followActivity := pub.FollowNew(pub.IRI(followActivityRecord.GetString("iri")), pub.IRI(followeeActor.GetString("iri")))
|
||||||
|
followActivity.Actor = pub.IRI(followActivityRecord.GetString("actor"))
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("type", string(pub.UndoType))
|
||||||
|
record.Set("object", followActivity)
|
||||||
|
record.Set("actor", followerActor.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
activity := pub.UndoNew(pub.IRI(id), followActivity)
|
||||||
|
activity.Actor = pub.IRI(followerActor.GetString("iri"))
|
||||||
|
|
||||||
|
return PostActivity(app, followerActor, activity, []string{followeeActor.GetString("inbox")})
|
||||||
|
}
|
||||||
|
|
||||||
|
// create outgoing unlike activity
|
||||||
|
func CreateUnlikeActivity(app core.App, like *core.Record) error {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
actor, err := app.FindRecordById("activitypub_actors", like.GetString("actor"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
trail, err := app.FindRecordById("trails", like.GetString("trail"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
trailAuthor, err := app.FindRecordById("activitypub_actors", trail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
object := trail.GetString("iri")
|
||||||
|
if object == "" {
|
||||||
|
// trail is local
|
||||||
|
object = fmt.Sprintf("%s/api/v1/trail/%s", origin, trail.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the original follow activity
|
||||||
|
likeActivityRecord, err := app.FindFirstRecordByFilter("activitypub_activities", "actor={:actor}&&object={:object}&&type={:type}", dbx.Params{"actor": actor.GetString("iri"), "object": object, "type": string(pub.LikeType)})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
likeActivity := pub.LikeNew(pub.IRI(likeActivityRecord.GetString("iri")), pub.IRI(object))
|
||||||
|
likeActivity.Actor = pub.IRI(likeActivityRecord.GetString("actor"))
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_activities")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
recordId := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/activity/%s", origin, recordId)
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.Set("id", recordId)
|
||||||
|
record.Set("iri", id)
|
||||||
|
record.Set("type", string(pub.UndoType))
|
||||||
|
record.Set("object", likeActivity)
|
||||||
|
record.Set("actor", actor.GetString("iri"))
|
||||||
|
record.Set("published", time.Now())
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
activity := pub.UndoNew(pub.IRI(id), likeActivity)
|
||||||
|
activity.Actor = pub.IRI(actor.GetString("iri"))
|
||||||
|
|
||||||
|
return PostActivity(app, actor, activity, []string{trailAuthor.GetString("inbox")})
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProcessUndoActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
|
||||||
|
if activity.Object.GetType() == pub.FollowType {
|
||||||
|
return processUnfollowActivity(app, actor, activity)
|
||||||
|
} else if activity.Object.GetType() == pub.LikeType {
|
||||||
|
return processUnlikeActivity(app, actor, activity)
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("unknown undo activity object type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func processUnfollowActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
// this was a local follow
|
||||||
|
if actor.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
followActivity := activity.Object.(*pub.Activity)
|
||||||
|
|
||||||
|
followee, err := app.FindFirstRecordByData("activitypub_actors", "iri", followActivity.Object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
follow, err := app.FindFirstRecordByFilter("follows", "follower={:follower} && followee={:followee}", dbx.Params{"follower": actor.Id, "followee": followee.Id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = app.Delete(follow)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processUnlikeActivity(app core.App, actor *core.Record, activity pub.Activity) error {
|
||||||
|
if actor.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
likeActivity := activity.Object.(*pub.Activity)
|
||||||
|
|
||||||
|
trailId := path.Base(likeActivity.Object.GetID().String())
|
||||||
|
trail, err := app.FindRecordById("trails", trailId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
like, err := app.FindFirstRecordByFilter("trail_like", "actor={:actor} && trail={:trail}", dbx.Params{"actor": actor.Id, "trail": trail.Id})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = app.Delete(like)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -11,9 +11,15 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
||||||
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
|
github.com/go-ap/errors v0.0.0-20250409143711-5686c11ae650 // indirect
|
||||||
|
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||||
|
github.com/gorilla/css v1.0.1 // indirect
|
||||||
github.com/twpayne/go-geom v1.6.1 // indirect
|
github.com/twpayne/go-geom v1.6.1 // indirect
|
||||||
|
github.com/valyala/fastjson v1.6.4 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,6 +32,8 @@ require (
|
|||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
github.com/ganigeorgiev/fexpr v0.4.1 // indirect
|
github.com/ganigeorgiev/fexpr v0.4.1 // indirect
|
||||||
|
github.com/go-ap/activitypub v0.0.0-20250409143848-7113328b1f3d
|
||||||
|
github.com/go-fed/httpsig v1.1.0
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
@@ -34,6 +42,7 @@ require (
|
|||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.27
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/spf13/cast v1.7.1
|
github.com/spf13/cast v1.7.1
|
||||||
|
|||||||
21
db/go.sum
21
db/go.sum
@@ -1,5 +1,7 @@
|
|||||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
|
||||||
|
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
||||||
github.com/alecthomas/assert/v2 v2.10.0 h1:jjRCHsj6hBJhkmhznrCzoNpbA3zqy0fYiUcYZP/GkPY=
|
github.com/alecthomas/assert/v2 v2.10.0 h1:jjRCHsj6hBJhkmhznrCzoNpbA3zqy0fYiUcYZP/GkPY=
|
||||||
github.com/alecthomas/assert/v2 v2.10.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
github.com/alecthomas/assert/v2 v2.10.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||||
@@ -9,6 +11,8 @@ github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer5
|
|||||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||||
|
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||||
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
@@ -28,6 +32,14 @@ github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3G
|
|||||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||||
github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k=
|
github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k=
|
||||||
github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
||||||
|
github.com/go-ap/activitypub v0.0.0-20250409143848-7113328b1f3d h1:IWrWGnmKzpHqginJ18ljKkty/X8glxM8Mg3pk6bkb8g=
|
||||||
|
github.com/go-ap/activitypub v0.0.0-20250409143848-7113328b1f3d/go.mod h1:EUtZuXtHo4yKkTJmcbAZYW+X1G2poeT8icmBh24eq7o=
|
||||||
|
github.com/go-ap/errors v0.0.0-20250409143711-5686c11ae650 h1:tlwla5IQUea0CuktkBd2FLDwVzts4OeTWPPkhQPSK5Q=
|
||||||
|
github.com/go-ap/errors v0.0.0-20250409143711-5686c11ae650/go.mod h1:Vkh+Z3f24K8nMsJKXo1FHn5ebPsXvB/WDH5JRtYqdNo=
|
||||||
|
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw=
|
||||||
|
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA=
|
||||||
|
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
|
||||||
|
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
@@ -45,6 +57,8 @@ github.com/google/pprof v0.0.0-20250315033105-103756e64e1d h1:tx51Lf+wdE+aavqH8T
|
|||||||
github.com/google/pprof v0.0.0-20250315033105-103756e64e1d/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
github.com/google/pprof v0.0.0-20250315033105-103756e64e1d/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
||||||
|
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
||||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
@@ -63,6 +77,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
|||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/meilisearch/meilisearch-go v0.29.0 h1:HZ9NEKN59USINQ/DXJge/aaXq8IrsKbXGTdAoBaaDz4=
|
github.com/meilisearch/meilisearch-go v0.29.0 h1:HZ9NEKN59USINQ/DXJge/aaXq8IrsKbXGTdAoBaaDz4=
|
||||||
github.com/meilisearch/meilisearch-go v0.29.0/go.mod h1:2cRCAn4ddySUsFfNDLVPod/plRibQsJkXF/4gLhxbOk=
|
github.com/meilisearch/meilisearch-go v0.29.0/go.mod h1:2cRCAn4ddySUsFfNDLVPod/plRibQsJkXF/4gLhxbOk=
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@@ -99,7 +115,10 @@ github.com/twpayne/go-gpx v1.5.0 h1:HvFSJ+0r0sbhOQ8mTvd0/n0FhcgjTFsKQGG6o7PV6G4=
|
|||||||
github.com/twpayne/go-gpx v1.5.0/go.mod h1:vjvu/125399qj6k+px2v2v8dm08DM4I4dFBJmHHt2TE=
|
github.com/twpayne/go-gpx v1.5.0/go.mod h1:vjvu/125399qj6k+px2v2v8dm08DM4I4dFBJmHHt2TE=
|
||||||
github.com/twpayne/go-polyline v1.1.1 h1:/tSF1BR7rN4HWj4XKqvRUNrCiYVMCvywxTFVofvDV0w=
|
github.com/twpayne/go-polyline v1.1.1 h1:/tSF1BR7rN4HWj4XKqvRUNrCiYVMCvywxTFVofvDV0w=
|
||||||
github.com/twpayne/go-polyline v1.1.1/go.mod h1:ybd9IWWivW/rlXPXuuckeKUyF3yrIim+iqA7kSl4NFY=
|
github.com/twpayne/go-polyline v1.1.1/go.mod h1:ybd9IWWivW/rlXPXuuckeKUyF3yrIim+iqA7kSl4NFY=
|
||||||
|
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||||
|
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
||||||
@@ -109,6 +128,7 @@ golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
|
|||||||
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
|
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
|
||||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||||
@@ -117,6 +137,7 @@ golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT
|
|||||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
|||||||
@@ -33,6 +33,15 @@ func SyncKomoot(app core.App) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
userId := i.GetString("user")
|
userId := i.GetString("user")
|
||||||
|
actor, err := app.FindFirstRecordByData("activitypub_actors", "user", userId)
|
||||||
|
if err != nil {
|
||||||
|
warning := fmt.Sprintf("no actor found for user: %s\n", userId)
|
||||||
|
fmt.Print(warning)
|
||||||
|
app.Logger().Warn(warning)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
actorId := actor.Id
|
||||||
|
|
||||||
komootString := i.GetString("komoot")
|
komootString := i.GetString("komoot")
|
||||||
komootIntegration := KomootIntegration{
|
komootIntegration := KomootIntegration{
|
||||||
Planned: true,
|
Planned: true,
|
||||||
@@ -71,7 +80,7 @@ func SyncKomoot(app core.App) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
hasNewTours, err = syncTrailWithTours(app, k, komootIntegration, userId, tours)
|
hasNewTours, err = syncTrailWithTours(app, k, komootIntegration, userId, actorId, tours)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
warning := fmt.Sprintf("error syncing komoot tours with trails: %v\n", err)
|
warning := fmt.Sprintf("error syncing komoot tours with trails: %v\n", err)
|
||||||
fmt.Print(warning)
|
fmt.Print(warning)
|
||||||
@@ -165,7 +174,7 @@ func (k *KomootApi) fetchTours(page int) ([]KomootTour, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (k *KomootApi) fetchDetailedTour(tour KomootTour) (*DetailedKomootTour, error) {
|
func (k *KomootApi) fetchDetailedTour(tour KomootTour) (*DetailedKomootTour, error) {
|
||||||
url := fmt.Sprintf("https://api.komoot.de/v007/tours/%d?_embedded=coordinates,way_types,surfaces,directions,participants,timeline,cover_images&directions=v2&fields=timeline&format=coordinate_array&timeline_highlights_fields=tips,recommenders", tour.ID)
|
url := fmt.Sprintf("https://api.komoot.de/v007/tours/%d?_embedded=coordinates,way_types,surfaces,directions,participants,timeline,cover_images&directions=v2&fields=timeline&format=coordinate_array&timeline_highlights_fields=tips,recommenders&page=2", tour.ID)
|
||||||
body, err := sendRequest(url, k.buildHeader())
|
body, err := sendRequest(url, k.buildHeader())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -176,7 +185,7 @@ func (k *KomootApi) fetchDetailedTour(tour KomootTour) (*DetailedKomootTour, err
|
|||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncTrailWithTours(app core.App, k *KomootApi, i KomootIntegration, user string, tours []KomootTour) (bool, error) {
|
func syncTrailWithTours(app core.App, k *KomootApi, i KomootIntegration, user string, actor string, tours []KomootTour) (bool, error) {
|
||||||
hasNewTours := false
|
hasNewTours := false
|
||||||
for _, tour := range tours {
|
for _, tour := range tours {
|
||||||
trails, err := app.FindRecordsByFilter("trails", "external_id = {:id}", "", 1, 0, dbx.Params{"id": strconv.Itoa(int(tour.ID))})
|
trails, err := app.FindRecordsByFilter("trails", "external_id = {:id}", "", 1, 0, dbx.Params{"id": strconv.Itoa(int(tour.ID))})
|
||||||
@@ -202,7 +211,7 @@ func syncTrailWithTours(app core.App, k *KomootApi, i KomootIntegration, user st
|
|||||||
app.Logger().Warn(fmt.Sprintf("Unable to create waypoints for tour '%s': %v", tour.Name, err))
|
app.Logger().Warn(fmt.Sprintf("Unable to create waypoints for tour '%s': %v", tour.Name, err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = createTrailFromTour(app, detailedTour, gpx, user, wpIds)
|
err = createTrailFromTour(app, k, detailedTour, gpx, actor, wpIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.Logger().Warn(fmt.Sprintf("Unable to create trail for tour '%s': %v", tour.Name, err))
|
app.Logger().Warn(fmt.Sprintf("Unable to create trail for tour '%s': %v", tour.Name, err))
|
||||||
continue
|
continue
|
||||||
@@ -212,27 +221,9 @@ func syncTrailWithTours(app core.App, k *KomootApi, i KomootIntegration, user st
|
|||||||
return hasNewTours, nil
|
return hasNewTours, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTrailFromTour(app core.App, detailedTour *DetailedKomootTour, gpx *filesystem.File, user string, wpIds []string) error {
|
func createTrailFromTour(app core.App, k *KomootApi, detailedTour *DetailedKomootTour, gpx *filesystem.File, actor string, wpIds []string) error {
|
||||||
var summitLogRecord *core.Record
|
trailid := security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet)
|
||||||
if detailedTour.Type == "tour_recorded" {
|
|
||||||
collection, err := app.FindCollectionByNameOrId("summit_logs")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
summitLogRecord = core.NewRecord(collection)
|
|
||||||
summitLogRecord.Load(map[string]any{
|
|
||||||
"distance": detailedTour.Distance,
|
|
||||||
"elevation_gain": detailedTour.ElevationUp,
|
|
||||||
"elevation_loss": detailedTour.ElevationDown,
|
|
||||||
"duration": detailedTour.Duration,
|
|
||||||
"date": detailedTour.Date,
|
|
||||||
"author": user,
|
|
||||||
})
|
|
||||||
if err := app.Save(summitLogRecord); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
collection, err := app.FindCollectionByNameOrId("trails")
|
collection, err := app.FindCollectionByNameOrId("trails")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -259,7 +250,7 @@ func createTrailFromTour(app core.App, detailedTour *DetailedKomootTour, gpx *fi
|
|||||||
|
|
||||||
var photos []*filesystem.File
|
var photos []*filesystem.File
|
||||||
if len(detailedTour.Embedded.CoverImages.Embedded.Items) > 0 {
|
if len(detailedTour.Embedded.CoverImages.Embedded.Items) > 0 {
|
||||||
photos, err = fetchRoutePhotos(detailedTour)
|
photos, err = fetchRoutePhotos(k, detailedTour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -277,6 +268,7 @@ func createTrailFromTour(app core.App, detailedTour *DetailedKomootTour, gpx *fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
record.Load(map[string]any{
|
record.Load(map[string]any{
|
||||||
|
"id": trailid,
|
||||||
"name": detailedTour.Name,
|
"name": detailedTour.Name,
|
||||||
"public": detailedTour.Status == "public",
|
"public": detailedTour.Status == "public",
|
||||||
"distance": detailedTour.Distance,
|
"distance": detailedTour.Distance,
|
||||||
@@ -291,12 +283,9 @@ func createTrailFromTour(app core.App, detailedTour *DetailedKomootTour, gpx *fi
|
|||||||
"difficulty": diffculty,
|
"difficulty": diffculty,
|
||||||
"category": categoryId,
|
"category": categoryId,
|
||||||
"waypoints": wpIds,
|
"waypoints": wpIds,
|
||||||
"author": user,
|
"author": actor,
|
||||||
})
|
})
|
||||||
|
|
||||||
if summitLogRecord != nil {
|
|
||||||
record.Set("summit_logs", summitLogRecord.Id)
|
|
||||||
}
|
|
||||||
if photos != nil {
|
if photos != nil {
|
||||||
record.Set("photos", photos)
|
record.Set("photos", photos)
|
||||||
}
|
}
|
||||||
@@ -308,6 +297,27 @@ func createTrailFromTour(app core.App, detailedTour *DetailedKomootTour, gpx *fi
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if detailedTour.Type == "tour_recorded" {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("summit_logs")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
summitLogRecord := core.NewRecord(collection)
|
||||||
|
summitLogRecord.Load(map[string]any{
|
||||||
|
"distance": detailedTour.Distance,
|
||||||
|
"elevation_gain": detailedTour.ElevationUp,
|
||||||
|
"elevation_loss": detailedTour.ElevationDown,
|
||||||
|
"duration": detailedTour.Duration,
|
||||||
|
"date": detailedTour.Date,
|
||||||
|
"author": actor,
|
||||||
|
"trail": trailid,
|
||||||
|
})
|
||||||
|
if err := app.Save(summitLogRecord); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,11 +375,22 @@ func createWaypointsFromTour(app core.App, tour *DetailedKomootTour, user string
|
|||||||
return wpIds, nil
|
return wpIds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchRoutePhotos(tour *DetailedKomootTour) ([]*filesystem.File, error) {
|
func fetchRoutePhotos(k *KomootApi, tour *DetailedKomootTour) ([]*filesystem.File, error) {
|
||||||
|
url := fmt.Sprintf("https://api.komoot.de/v007/tours/%d/cover_images/", tour.ID)
|
||||||
|
body, err := sendRequest(url, k.buildHeader())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
photos := make([]*filesystem.File, len(tour.Embedded.CoverImages.Embedded.Items))
|
var data *CoverImages
|
||||||
|
err = json.Unmarshal(body, &data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
for i, img := range tour.Embedded.CoverImages.Embedded.Items {
|
photos := make([]*filesystem.File, data.Page.TotalElements)
|
||||||
|
|
||||||
|
for i, img := range data.Embedded.Items {
|
||||||
photo, err := fetchPhoto(img.Src, "", "")
|
photo, err := fetchPhoto(img.Src, "", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -36,9 +36,18 @@ func SyncStrava(app core.App) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
userId := i.GetString("user")
|
userId := i.GetString("user")
|
||||||
|
actor, err := app.FindFirstRecordByData("activitypub_actors", "user", userId)
|
||||||
|
if err != nil {
|
||||||
|
warning := fmt.Sprintf("no actor found for user: %s\n", userId)
|
||||||
|
fmt.Print(warning)
|
||||||
|
app.Logger().Warn(warning)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
actorId := actor.Id
|
||||||
|
|
||||||
stravaString := i.GetString("strava")
|
stravaString := i.GetString("strava")
|
||||||
var stravaIntegration StravaIntegration
|
var stravaIntegration StravaIntegration
|
||||||
err := json.Unmarshal([]byte(stravaString), &stravaIntegration)
|
err = json.Unmarshal([]byte(stravaString), &stravaIntegration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -103,7 +112,7 @@ func SyncStrava(app core.App) error {
|
|||||||
app.Logger().Warn(warning)
|
app.Logger().Warn(warning)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
hasNewRoutes, err = syncTrailsWithRoutes(app, r.AccessToken, userId, routes)
|
hasNewRoutes, err = syncTrailsWithRoutes(app, r.AccessToken, userId, actorId, routes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
warning := fmt.Sprintf("error syncing strava routes with trails: %v\n", err)
|
warning := fmt.Sprintf("error syncing strava routes with trails: %v\n", err)
|
||||||
fmt.Print(warning)
|
fmt.Print(warning)
|
||||||
@@ -124,7 +133,7 @@ func SyncStrava(app core.App) error {
|
|||||||
app.Logger().Warn(warning)
|
app.Logger().Warn(warning)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
hasNewActivities, err = syncTrailsWithActivities(app, r.AccessToken, userId, activities)
|
hasNewActivities, err = syncTrailsWithActivities(app, r.AccessToken, userId, actorId, activities)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
warning := fmt.Sprintf("error syncing strava activities with trails: %v", err)
|
warning := fmt.Sprintf("error syncing strava activities with trails: %v", err)
|
||||||
fmt.Print(warning)
|
fmt.Print(warning)
|
||||||
@@ -226,7 +235,7 @@ func fetchStravaActivities(accessToken string, page int) ([]StravaActivity, erro
|
|||||||
return activities, nil
|
return activities, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncTrailsWithRoutes(app core.App, accessToken string, user string, routes []StravaRoute) (bool, error) {
|
func syncTrailsWithRoutes(app core.App, accessToken string, user string, actor string, routes []StravaRoute) (bool, error) {
|
||||||
hasNewRoutes := false
|
hasNewRoutes := false
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
trails, err := app.FindRecordsByFilter("trails", "external_id = {:id}", "", 1, 0, dbx.Params{"id": route.IDStr})
|
trails, err := app.FindRecordsByFilter("trails", "external_id = {:id}", "", 1, 0, dbx.Params{"id": route.IDStr})
|
||||||
@@ -247,7 +256,7 @@ func syncTrailsWithRoutes(app core.App, accessToken string, user string, routes
|
|||||||
app.Logger().Warn(fmt.Sprintf("Unable to create waypoints for route '%s': %v", route.Name, err))
|
app.Logger().Warn(fmt.Sprintf("Unable to create waypoints for route '%s': %v", route.Name, err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = createTrailFromRoute(app, route, gpx, user, wpIds)
|
err = createTrailFromRoute(app, route, gpx, actor, wpIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.Logger().Warn(fmt.Sprintf("Unable to create trail for route '%s': %v", route.Name, err))
|
app.Logger().Warn(fmt.Sprintf("Unable to create trail for route '%s': %v", route.Name, err))
|
||||||
continue
|
continue
|
||||||
@@ -296,7 +305,7 @@ func fetchRouteGPX(route StravaRoute, accessToken string) (*filesystem.File, err
|
|||||||
return gpxFile, nil
|
return gpxFile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTrailFromRoute(app core.App, route StravaRoute, gpx *filesystem.File, user string, wpIds []string) error {
|
func createTrailFromRoute(app core.App, route StravaRoute, gpx *filesystem.File, actor string, wpIds []string) error {
|
||||||
collection, err := app.FindCollectionByNameOrId("trails")
|
collection, err := app.FindCollectionByNameOrId("trails")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -342,7 +351,7 @@ func createTrailFromRoute(app core.App, route StravaRoute, gpx *filesystem.File,
|
|||||||
"waypoints": wpIds,
|
"waypoints": wpIds,
|
||||||
"difficulty": "easy",
|
"difficulty": "easy",
|
||||||
"category": category,
|
"category": category,
|
||||||
"author": user,
|
"author": actor,
|
||||||
})
|
})
|
||||||
|
|
||||||
if gpx != nil {
|
if gpx != nil {
|
||||||
@@ -383,7 +392,7 @@ func createWaypointsFromRoute(app core.App, route StravaRoute, user string) ([]s
|
|||||||
return wpIds, nil
|
return wpIds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncTrailsWithActivities(app core.App, accessToken string, user string, activities []StravaActivity) (bool, error) {
|
func syncTrailsWithActivities(app core.App, accessToken string, user string, actor string, activities []StravaActivity) (bool, error) {
|
||||||
hasNewActivites := false
|
hasNewActivites := false
|
||||||
for _, activity := range activities {
|
for _, activity := range activities {
|
||||||
trails, err := app.FindRecordsByFilter("trails", "external_id = {:id}", "", 1, 0, dbx.Params{"id": strconv.Itoa(int(activity.ID))})
|
trails, err := app.FindRecordsByFilter("trails", "external_id = {:id}", "", 1, 0, dbx.Params{"id": strconv.Itoa(int(activity.ID))})
|
||||||
@@ -404,7 +413,7 @@ func syncTrailsWithActivities(app core.App, accessToken string, user string, act
|
|||||||
app.Logger().Warn(fmt.Sprintf("Unable to fetch GPX for activity '%s': %v", activity.Name, err))
|
app.Logger().Warn(fmt.Sprintf("Unable to fetch GPX for activity '%s': %v", activity.Name, err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = createTrailFromActivity(app, detailedActivity, gpx, user)
|
err = createTrailFromActivity(app, detailedActivity, gpx, actor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.Logger().Warn(fmt.Sprintf("Unable to create trail from activity '%s': %v", activity.Name, err))
|
app.Logger().Warn(fmt.Sprintf("Unable to create trail from activity '%s': %v", activity.Name, err))
|
||||||
continue
|
continue
|
||||||
|
|||||||
734
db/main.go
734
db/main.go
@@ -1,13 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/rand/v2"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -21,11 +20,15 @@ import (
|
|||||||
"github.com/pocketbase/pocketbase/tools/security"
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
|
|
||||||
|
"pocketbase/federation"
|
||||||
"pocketbase/integrations/komoot"
|
"pocketbase/integrations/komoot"
|
||||||
"pocketbase/integrations/strava"
|
"pocketbase/integrations/strava"
|
||||||
|
|
||||||
_ "pocketbase/migrations"
|
_ "pocketbase/migrations"
|
||||||
"pocketbase/util"
|
"pocketbase/util"
|
||||||
|
|
||||||
|
pub "github.com/go-ap/activitypub"
|
||||||
|
"github.com/microcosm-cc/bluemonday"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultMeiliMasterKey = "vODkljPcfFANYNepCHyDyGjzAMPcdHnrb6X5KyXQPWo"
|
const defaultMeiliMasterKey = "vODkljPcfFANYNepCHyDyGjzAMPcdHnrb6X5KyXQPWo"
|
||||||
@@ -86,18 +89,29 @@ func setupEventHandlers(app *pocketbase.PocketBase, client meilisearch.ServiceMa
|
|||||||
app.OnRecordAfterUpdateSuccess("trails").BindFunc(updateTrailHandler(client))
|
app.OnRecordAfterUpdateSuccess("trails").BindFunc(updateTrailHandler(client))
|
||||||
app.OnRecordAfterDeleteSuccess("trails").BindFunc(deleteTrailHandler(client))
|
app.OnRecordAfterDeleteSuccess("trails").BindFunc(deleteTrailHandler(client))
|
||||||
|
|
||||||
app.OnRecordAfterCreateSuccess("trail_share").BindFunc(createTrailShareHandler(client))
|
app.OnRecordCreateRequest("summit_logs").BindFunc(createSummitLogHandler())
|
||||||
app.OnRecordAfterDeleteSuccess("trail_share").BindFunc(deleteTrailShareHandler(client))
|
app.OnRecordUpdateRequest("summit_logs").BindFunc(updateSummitLogHandler())
|
||||||
|
app.OnRecordDeleteRequest("summit_logs").BindFunc(deleteSummitLogHandler())
|
||||||
|
|
||||||
|
app.OnRecordCreateRequest("comments").BindFunc(createCommentHandler())
|
||||||
|
app.OnRecordUpdateRequest("comments").BindFunc(updateCommentHandler())
|
||||||
|
app.OnRecordDeleteRequest("comments").BindFunc(deleteCommentHandler(client))
|
||||||
|
|
||||||
|
app.OnRecordCreateRequest("trail_share").BindFunc(createTrailShareHandler(client))
|
||||||
|
app.OnRecordDeleteRequest("trail_share").BindFunc(deleteTrailShareHandler(client))
|
||||||
|
|
||||||
|
app.OnRecordAfterCreateSuccess("trail_like").BindFunc(createTrailLikeHandler(client))
|
||||||
|
app.OnRecordAfterDeleteSuccess("trail_like").BindFunc(deleteTrailLikeHandler(client))
|
||||||
|
|
||||||
app.OnRecordAfterCreateSuccess("lists").BindFunc(createListHandler(client))
|
app.OnRecordAfterCreateSuccess("lists").BindFunc(createListHandler(client))
|
||||||
app.OnRecordAfterUpdateSuccess("lists").BindFunc(updateListHandler(client))
|
app.OnRecordAfterUpdateSuccess("lists").BindFunc(updateListHandler(client))
|
||||||
app.OnRecordAfterDeleteSuccess("lists").BindFunc(deleteListHandler(client))
|
app.OnRecordAfterDeleteSuccess("lists").BindFunc(deleteListHandler(client))
|
||||||
|
|
||||||
app.OnRecordAfterCreateSuccess("list_share").BindFunc(createListShareHandler(client))
|
app.OnRecordCreateRequest("list_share").BindFunc(createListShareHandler(client))
|
||||||
app.OnRecordAfterDeleteSuccess("list_share").BindFunc(deleteListShareHandler(client))
|
app.OnRecordDeleteRequest("list_share").BindFunc(deleteListShareHandler(client))
|
||||||
|
|
||||||
app.OnRecordAfterCreateSuccess("follows").BindFunc(createFollowHandler())
|
app.OnRecordCreateRequest("follows").BindFunc(createFollowHandler())
|
||||||
app.OnRecordAfterCreateSuccess("comments").BindFunc(createCommentHandler())
|
app.OnRecordDeleteRequest("follows").BindFunc(deleteFollowHandler())
|
||||||
|
|
||||||
app.OnRecordsListRequest("integrations").BindFunc(listIntegrationHandler())
|
app.OnRecordsListRequest("integrations").BindFunc(listIntegrationHandler())
|
||||||
app.OnRecordCreate("integrations").BindFunc(createIntegrationHandler())
|
app.OnRecordCreate("integrations").BindFunc(createIntegrationHandler())
|
||||||
@@ -105,22 +119,72 @@ func setupEventHandlers(app *pocketbase.PocketBase, client meilisearch.ServiceMa
|
|||||||
app.OnRecordUpdate("integrations").BindFunc(updateIntegrationHandler())
|
app.OnRecordUpdate("integrations").BindFunc(updateIntegrationHandler())
|
||||||
app.OnRecordAfterUpdateSuccess("integrations").BindFunc(createUpdateIntegrationSuccessHandler())
|
app.OnRecordAfterUpdateSuccess("integrations").BindFunc(createUpdateIntegrationSuccessHandler())
|
||||||
|
|
||||||
|
app.OnRecordCreateRequest().BindFunc(sanitizeHTML())
|
||||||
|
app.OnRecordUpdateRequest().BindFunc(sanitizeHTML())
|
||||||
|
|
||||||
app.OnRecordRequestEmailChangeRequest("users").BindFunc(changeUserEmailHandler())
|
app.OnRecordRequestEmailChangeRequest("users").BindFunc(changeUserEmailHandler())
|
||||||
app.OnServe().BindFunc(onBeforeServeHandler(client))
|
app.OnServe().BindFunc(onBeforeServeHandler(client))
|
||||||
|
|
||||||
app.OnBootstrap().BindFunc(onBootstrapHandler())
|
app.OnBootstrap().BindFunc(onBootstrapHandler())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sanitizeHTML() func(e *core.RecordRequestEvent) error {
|
||||||
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
fieldsToSanitize := map[string][]string{
|
||||||
|
"lists": {"description"},
|
||||||
|
"settings": {"bio"},
|
||||||
|
"summit_logs": {"text"},
|
||||||
|
"trails": {"description"},
|
||||||
|
"comments": {"text"},
|
||||||
|
"waypoints": {"description"},
|
||||||
|
}
|
||||||
|
collection := e.Collection.Name
|
||||||
|
fields, ok := fieldsToSanitize[collection]
|
||||||
|
if !ok {
|
||||||
|
return e.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
p := bluemonday.NewPolicy()
|
||||||
|
p.AllowStandardAttributes()
|
||||||
|
p.AllowStandardURLs()
|
||||||
|
p.AllowLists()
|
||||||
|
p.AllowElements("br", "div", "hr", "p", "span", "wbr")
|
||||||
|
p.AllowElements("b", "strong", "em", "u", "blockquote", "a")
|
||||||
|
p.AllowAttrs("href").OnElements("a")
|
||||||
|
p.AllowAttrs("target").OnElements("a")
|
||||||
|
p.AllowAttrs("class").OnElements("a")
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
if val, ok := e.Record.Get(field).(string); ok {
|
||||||
|
sanitizedValue := p.Sanitize(val)
|
||||||
|
e.Record.Set(field, sanitizedValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createUserHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
func createUserHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordEvent) error {
|
||||||
userId := e.Record.Id
|
userId := e.Record.Id
|
||||||
|
|
||||||
|
err := createDefaultUserSettings(e.App, e.Record.Id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
actor, err := util.ActorFromUser(e.App, e.Record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
searchRules := map[string]interface{}{
|
searchRules := map[string]interface{}{
|
||||||
"lists": map[string]string{
|
"lists": map[string]string{
|
||||||
"filter": "public = true OR author = " + userId + " OR shares = " + userId,
|
"filter": "public = true OR author = " + actor.Id + " OR shares = " + userId,
|
||||||
},
|
},
|
||||||
"trails": map[string]string{
|
"trails": map[string]string{
|
||||||
"filter": "public = true OR author = " + userId + " OR shares = " + userId,
|
"filter": "public = true OR author = " + actor.Id + " OR shares = " + userId,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,10 +197,6 @@ func createUserHandler(client meilisearch.ServiceManager) func(e *core.RecordEve
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = createDefaultUserSettings(e.App, e.Record.Id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return e.Next()
|
return e.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,37 +217,38 @@ func createDefaultUserSettings(app core.App, userId string) error {
|
|||||||
func createTrailHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
func createTrailHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordEvent) error {
|
||||||
record := e.Record
|
record := e.Record
|
||||||
author, err := e.App.FindRecordById("users", record.GetString(("author")))
|
author, err := e.App.FindRecordById("activitypub_actors", record.GetString(("author")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := util.IndexTrail(e.App, record, author, client); err != nil {
|
if err := util.IndexTrail(e.App, record, author, client); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if !author.GetBool("isLocal") {
|
||||||
if record.GetBool("public") {
|
// this happens if someone fetches a remote trail
|
||||||
notification := util.Notification{
|
// we create a stub trail record for later reference
|
||||||
Type: util.TrailCreate,
|
// no need to create an activity for that
|
||||||
Metadata: map[string]string{
|
return e.Next()
|
||||||
"id": record.Id,
|
|
||||||
"trail": record.GetString("name"),
|
|
||||||
},
|
|
||||||
Seen: false,
|
|
||||||
Author: record.GetString("author"),
|
|
||||||
}
|
|
||||||
err = util.SendNotificationToFollowers(e.App, notification)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return e.Next()
|
|
||||||
|
err = e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = federation.CreateTrailActivity(e.App, e.Record, pub.CreateType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateTrailHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
func updateTrailHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordEvent) error {
|
||||||
record := e.Record
|
record := e.Record
|
||||||
author, err := e.App.FindRecordById("users", record.GetString(("author")))
|
author, err := e.App.FindRecordById("activitypub_actors", record.GetString(("author")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -195,7 +256,24 @@ func updateTrailHandler(client meilisearch.ServiceManager) func(e *core.RecordEv
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return e.Next()
|
if !author.GetBool("isLocal") {
|
||||||
|
// this happens if someone fetches a remote trail
|
||||||
|
// we create a stub trail record for later reference
|
||||||
|
// no need to create an activity for that
|
||||||
|
return e.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = federation.CreateTrailActivity(e.App, e.Record, pub.UpdateType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,12 +291,100 @@ func deleteTrailHandler(client meilisearch.ServiceManager) func(e *core.RecordEv
|
|||||||
log.Fatalf("Error waiting for task completion: %v", err)
|
log.Fatalf("Error waiting for task completion: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = federation.CreateTrailDeleteActivity(e.App, e.Record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return e.Next()
|
return e.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTrailShareHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
func createSummitLogHandler() func(e *core.RecordRequestEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
|
||||||
|
err := e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = federation.CreateSummitLogActivity(e.App, e.Record, pub.CreateType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateSummitLogHandler() func(e *core.RecordRequestEvent) error {
|
||||||
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
|
||||||
|
err := e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = federation.CreateSummitLogActivity(e.App, e.Record, pub.UpdateType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteSummitLogHandler() func(e *core.RecordRequestEvent) error {
|
||||||
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
err := federation.CreateSummitLogDeleteActivity(e.App, e.Record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createCommentHandler() func(e *core.RecordRequestEvent) error {
|
||||||
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
|
||||||
|
e.Next()
|
||||||
|
|
||||||
|
err := federation.CreateCommentActivity(e.App, e.Record, pub.CreateType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateCommentHandler() func(e *core.RecordRequestEvent) error {
|
||||||
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
err := federation.CreateCommentActivity(e.App, e.Record, pub.UpdateType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteCommentHandler(client meilisearch.ServiceManager) func(e *core.RecordRequestEvent) error {
|
||||||
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
|
||||||
|
err := federation.CreateCommentDeleteActivity(e.App, client, e.Record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTrailShareHandler(client meilisearch.ServiceManager) func(e *core.RecordRequestEvent) error {
|
||||||
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
err := e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
record := e.Record
|
record := e.Record
|
||||||
|
|
||||||
trailId := record.GetString("trail")
|
trailId := record.GetString("trail")
|
||||||
@@ -228,42 +394,26 @@ func createTrailShareHandler(client meilisearch.ServiceManager) func(e *core.Rec
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
userIds := make([]string, len(shares))
|
actorIds := make([]string, len(shares))
|
||||||
for i, r := range shares {
|
for i, r := range shares {
|
||||||
userIds[i] = r.GetString("user")
|
actorIds[i] = r.GetString("actor")
|
||||||
}
|
}
|
||||||
err = util.UpdateTrailShares(trailId, userIds, client)
|
err = util.UpdateTrailShares(trailId, actorIds, client)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs := e.App.ExpandRecord(record, []string{"trail", "trail.author"}, nil); len(errs) > 0 {
|
err = federation.CreateAnnounceActivity(e.App, record, federation.TrailAnnounceType)
|
||||||
return fmt.Errorf("failed to expand: %v", errs)
|
|
||||||
}
|
|
||||||
shareTrail := record.ExpandedOne("trail")
|
|
||||||
shareTrailAuthor := shareTrail.ExpandedOne("author")
|
|
||||||
|
|
||||||
notification := util.Notification{
|
|
||||||
Type: util.TrailShare,
|
|
||||||
Metadata: map[string]string{
|
|
||||||
"id": shareTrail.Id,
|
|
||||||
"trail": shareTrail.GetString("name"),
|
|
||||||
"author": shareTrailAuthor.GetString("username"),
|
|
||||||
},
|
|
||||||
Seen: false,
|
|
||||||
Author: shareTrailAuthor.Id,
|
|
||||||
}
|
|
||||||
err = util.SendNotification(e.App, notification, record.GetString("user"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return e.Next()
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteTrailShareHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
func deleteTrailShareHandler(client meilisearch.ServiceManager) func(e *core.RecordRequestEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordRequestEvent) error {
|
||||||
record := e.Record
|
record := e.Record
|
||||||
|
|
||||||
trailId := record.GetString("trail")
|
trailId := record.GetString("trail")
|
||||||
@@ -275,42 +425,178 @@ func deleteTrailShareHandler(client meilisearch.ServiceManager) func(e *core.Rec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createTrailLikeHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
||||||
|
return func(e *core.RecordEvent) error {
|
||||||
|
err := e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
record := e.Record
|
||||||
|
|
||||||
|
trailId := record.GetString("trail")
|
||||||
|
actorId := record.GetString("actor")
|
||||||
|
actor, err := e.App.FindRecordById("activitypub_actors", actorId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
trail, err := e.App.FindRecordById("trails", trailId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
likes, err := e.App.FindAllRecords("trail_like",
|
||||||
|
dbx.NewExp("trail = {:trailId}", dbx.Params{"trailId": trailId}),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
trail.Set("like_count", len(likes))
|
||||||
|
err = e.App.UnsafeWithoutHooks().Save(trail)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
actorIds := make([]string, len(likes))
|
||||||
|
for i, r := range likes {
|
||||||
|
actorIds[i] = r.GetString("actor")
|
||||||
|
}
|
||||||
|
err = util.UpdateTrailLikes(trailId, actorIds, client)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !actor.GetBool("isLocal") {
|
||||||
|
// this happens if someone likes a remote trail
|
||||||
|
// we create a local copy
|
||||||
|
// no need to create an activity for that
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = federation.CreateLikeActivity(e.App, record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteTrailLikeHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
||||||
|
return func(e *core.RecordEvent) error {
|
||||||
|
|
||||||
|
record := e.Record
|
||||||
|
|
||||||
|
trailId := record.GetString("trail")
|
||||||
|
actorId := record.GetString("actor")
|
||||||
|
actor, err := e.App.FindRecordById("activitypub_actors", actorId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// trail might deleted be already if this is called as part of a cascade
|
||||||
|
trail, err := e.App.FindRecordById("trails", trailId)
|
||||||
|
if err != nil && err == sql.ErrNoRows {
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
likes, err := e.App.CountRecords("trail_like", dbx.NewExp("trail={:trail}", dbx.Params{"trail": trailId}))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
trail.Set("like_count", likes)
|
||||||
|
err = e.App.UnsafeWithoutHooks().Save(trail)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = util.UpdateTrailLikes(trailId, []string{}, client)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !actor.GetBool("isLocal") {
|
||||||
|
// this happens if someone likes a remote trail
|
||||||
|
// we create a local copy
|
||||||
|
// no need to create an activity for that
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = federation.CreateUnlikeActivity(e.App, record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createListHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
func createListHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordEvent) error {
|
||||||
record := e.Record
|
record := e.Record
|
||||||
|
|
||||||
if err := util.IndexList(record, client); err != nil {
|
author, err := e.App.FindRecordById("activitypub_actors", record.GetString(("author")))
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !record.GetBool("public") {
|
|
||||||
return e.Next()
|
|
||||||
}
|
|
||||||
notification := util.Notification{
|
|
||||||
Type: util.ListCreate,
|
|
||||||
Metadata: map[string]string{
|
|
||||||
"id": record.Id,
|
|
||||||
"list": record.GetString("name"),
|
|
||||||
},
|
|
||||||
Seen: false,
|
|
||||||
Author: record.GetString("author"),
|
|
||||||
}
|
|
||||||
err := util.SendNotificationToFollowers(e.App, notification)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return e.Next()
|
|
||||||
|
if err := util.IndexList(e.App, record, author, client); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !author.GetBool("isLocal") {
|
||||||
|
// this happens if someone fetches a remote list
|
||||||
|
// we create a stub list record for later reference
|
||||||
|
// no need to create an activity for that
|
||||||
|
return e.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = federation.CreateListActivity(e.App, e.Record, pub.CreateType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateListHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
func updateListHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordEvent) error {
|
||||||
record := e.Record
|
record := e.Record
|
||||||
err := util.UpdateList(record, client)
|
author, err := e.App.FindRecordById("activitypub_actors", record.GetString(("author")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.Next()
|
err = util.UpdateList(e.App, record, author, client)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !author.GetBool("isLocal") {
|
||||||
|
// this happens if someone fetches a remote list
|
||||||
|
// we create a stub list record for later reference
|
||||||
|
// no need to create an activity for that
|
||||||
|
return e.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
err = e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = federation.CreateListActivity(e.App, e.Record, pub.CreateType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,12 +608,22 @@ func deleteListHandler(client meilisearch.ServiceManager) func(e *core.RecordEve
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = federation.CreateListDeleteActivity(e.App, record)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return e.Next()
|
return e.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createListShareHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
func createListShareHandler(client meilisearch.ServiceManager) func(e *core.RecordRequestEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordRequestEvent) error {
|
||||||
|
err := e.Next()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
record := e.Record
|
record := e.Record
|
||||||
listId := record.GetString("list")
|
listId := record.GetString("list")
|
||||||
shares, err := e.App.FindAllRecords("list_share",
|
shares, err := e.App.FindAllRecords("list_share",
|
||||||
@@ -336,42 +632,27 @@ func createListShareHandler(client meilisearch.ServiceManager) func(e *core.Reco
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
userIds := make([]string, len(shares))
|
actorIds := make([]string, len(shares))
|
||||||
for i, r := range shares {
|
for i, r := range shares {
|
||||||
userIds[i] = r.GetString("user")
|
actorIds[i] = r.GetString("actor")
|
||||||
}
|
}
|
||||||
err = util.UpdateListShares(listId, userIds, client)
|
err = util.UpdateListShares(listId, actorIds, client)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs := e.App.ExpandRecord(record, []string{"list", "list.author"}, nil); len(errs) > 0 {
|
err = federation.CreateAnnounceActivity(e.App, record, federation.ListAnnounceType)
|
||||||
return fmt.Errorf("failed to expand: %v", errs)
|
|
||||||
}
|
|
||||||
shareList := record.ExpandedOne("list")
|
|
||||||
shareListAuthor := shareList.ExpandedOne("author")
|
|
||||||
|
|
||||||
notification := util.Notification{
|
|
||||||
Type: util.ListShare,
|
|
||||||
Metadata: map[string]string{
|
|
||||||
"id": shareList.Id,
|
|
||||||
"list": shareList.GetString("name"),
|
|
||||||
"author": shareListAuthor.GetString("username"),
|
|
||||||
},
|
|
||||||
Seen: false,
|
|
||||||
Author: shareListAuthor.Id,
|
|
||||||
}
|
|
||||||
err = util.SendNotification(e.App, notification, record.GetString("user"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return e.Next()
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteListShareHandler(client meilisearch.ServiceManager) func(e *core.RecordEvent) error {
|
func deleteListShareHandler(client meilisearch.ServiceManager) func(e *core.RecordRequestEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordRequestEvent) error {
|
||||||
record := e.Record
|
record := e.Record
|
||||||
listId := record.GetString("list")
|
listId := record.GetString("list")
|
||||||
err := util.UpdateListShares(listId, []string{}, client)
|
err := util.UpdateListShares(listId, []string{}, client)
|
||||||
@@ -382,55 +663,56 @@ func deleteListShareHandler(client meilisearch.ServiceManager) func(e *core.Reco
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFollowHandler() func(e *core.RecordEvent) error {
|
func createFollowHandler() func(e *core.RecordRequestEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordRequestEvent) error {
|
||||||
record := e.Record
|
// record := e.Record
|
||||||
if errs := e.App.ExpandRecord(record, []string{"follower"}, nil); len(errs) > 0 {
|
// if errs := e.App.ExpandRecord(record, []string{"follower"}, nil); len(errs) > 0 {
|
||||||
return fmt.Errorf("failed to expand: %v", errs)
|
// return fmt.Errorf("failed to expand: %v", errs)
|
||||||
}
|
// }
|
||||||
follower := record.ExpandedOne("follower")
|
// follower := record.ExpandedOne("follower")
|
||||||
|
|
||||||
notification := util.Notification{
|
// notification := util.Notification{
|
||||||
Type: util.NewFollower,
|
// Type: util.NewFollower,
|
||||||
Metadata: map[string]string{
|
// Metadata: map[string]string{
|
||||||
"follower": follower.GetString("username"),
|
// "follower": follower.GetString("username"),
|
||||||
},
|
// },
|
||||||
Seen: false,
|
// Seen: false,
|
||||||
Author: record.GetString("follower"),
|
// Author: record.GetString("follower"),
|
||||||
}
|
// }
|
||||||
err := util.SendNotification(e.App, notification, record.GetString("followee"))
|
// err := util.SendNotification(e.App, notification, record.GetString("followee"))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
return e.Next()
|
e.Next()
|
||||||
|
federation.CreateFollowActivity(e.App, e.Record)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createCommentHandler() func(e *core.RecordEvent) error {
|
func deleteFollowHandler() func(e *core.RecordRequestEvent) error {
|
||||||
return func(e *core.RecordEvent) error {
|
return func(e *core.RecordRequestEvent) error {
|
||||||
record := e.Record
|
// record := e.Record
|
||||||
|
// if errs := e.App.ExpandRecord(record, []string{"follower"}, nil); len(errs) > 0 {
|
||||||
|
// return fmt.Errorf("failed to expand: %v", errs)
|
||||||
|
// }
|
||||||
|
// follower := record.ExpandedOne("follower")
|
||||||
|
|
||||||
if errs := e.App.ExpandRecord(record, []string{"trail", "author"}, nil); len(errs) > 0 {
|
// notification := util.Notification{
|
||||||
return fmt.Errorf("failed to expand: %v", errs)
|
// Type: util.NewFollower,
|
||||||
}
|
// Metadata: map[string]string{
|
||||||
commentAuthor := record.ExpandedOne("author")
|
// "follower": follower.GetString("username"),
|
||||||
commentTrail := record.ExpandedOne("trail")
|
// },
|
||||||
|
// Seen: false,
|
||||||
|
// Author: record.GetString("follower"),
|
||||||
|
// }
|
||||||
|
// err := util.SendNotification(e.App, notification, record.GetString("followee"))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
federation.CreateUnfollowActivity(e.App, e.Record)
|
||||||
|
|
||||||
notification := util.Notification{
|
|
||||||
Type: util.TrailComment,
|
|
||||||
Metadata: map[string]string{
|
|
||||||
"id": commentTrail.Id,
|
|
||||||
"author": commentAuthor.GetString("username"),
|
|
||||||
"trail": commentTrail.GetString("name"),
|
|
||||||
"comment": record.GetString("text"),
|
|
||||||
},
|
|
||||||
Seen: false,
|
|
||||||
Author: record.GetString("author"),
|
|
||||||
}
|
|
||||||
err := util.SendNotification(e.App, notification, commentTrail.GetString("author"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return e.Next()
|
return e.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -637,46 +919,6 @@ func registerRoutes(se *core.ServeEvent, client meilisearch.ServiceManager) {
|
|||||||
}
|
}
|
||||||
return e.JSON(http.StatusOK, map[string]string{"token": token})
|
return e.JSON(http.StatusOK, map[string]string{"token": token})
|
||||||
})
|
})
|
||||||
se.Router.GET("/trail/recommend", func(e *core.RequestEvent) error {
|
|
||||||
qSize := e.Request.URL.Query().Get("size")
|
|
||||||
size, err := strconv.Atoi(qSize)
|
|
||||||
if err != nil {
|
|
||||||
size = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
userId := ""
|
|
||||||
if e.Auth != nil {
|
|
||||||
userId = e.Auth.Id
|
|
||||||
}
|
|
||||||
|
|
||||||
trails, err := e.App.FindRecordsByFilter(
|
|
||||||
"trails",
|
|
||||||
"author = {:userId} || public = true || ({:userId} != '' && trail_share_via_trail.user ?= {:userId})",
|
|
||||||
"",
|
|
||||||
-1,
|
|
||||||
0,
|
|
||||||
dbx.Params{"userId": userId},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, t := range trails {
|
|
||||||
errs := e.App.ExpandRecord(t, []string{"tags"}, nil)
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(trails) < size {
|
|
||||||
size = len(trails)
|
|
||||||
}
|
|
||||||
rand.Shuffle(len(trails), func(i, j int) {
|
|
||||||
trails[i], trails[j] = trails[j], trails[i]
|
|
||||||
})
|
|
||||||
randomTrails := trails[:size]
|
|
||||||
return e.JSON(http.StatusOK, randomTrails)
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
se.Router.POST("/integration/strava/token", func(e *core.RequestEvent) error {
|
se.Router.POST("/integration/strava/token", func(e *core.RequestEvent) error {
|
||||||
encryptionKey := os.Getenv("POCKETBASE_ENCRYPTION_KEY")
|
encryptionKey := os.Getenv("POCKETBASE_ENCRYPTION_KEY")
|
||||||
@@ -792,6 +1034,61 @@ func registerRoutes(se *core.ServeEvent, client meilisearch.ServiceManager) {
|
|||||||
|
|
||||||
return e.JSON(http.StatusOK, nil)
|
return e.JSON(http.StatusOK, nil)
|
||||||
})
|
})
|
||||||
|
se.Router.POST("/activitypub/activity/process", federation.ProcessActivity)
|
||||||
|
se.Router.GET("/activitypub/actor", func(e *core.RequestEvent) error {
|
||||||
|
resource := e.Request.URL.Query().Get("resource")
|
||||||
|
resource = strings.TrimPrefix(resource, "acct:")
|
||||||
|
|
||||||
|
iri := e.Request.URL.Query().Get("iri")
|
||||||
|
follows := e.Request.URL.Query().Get("follows") == "true"
|
||||||
|
|
||||||
|
var actor *core.Record
|
||||||
|
var err error
|
||||||
|
if resource != "" {
|
||||||
|
actor, err = federation.GetActorByHandle(e.App, resource, follows)
|
||||||
|
} else {
|
||||||
|
actor, err = federation.GetActorByIRI(e.App, iri, follows)
|
||||||
|
}
|
||||||
|
if err != nil && actor == nil {
|
||||||
|
if strings.HasPrefix(err.Error(), "webfinger") || err.Error() == "profile is private" {
|
||||||
|
return e.NotFoundError("Not found", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
} else if err != nil && actor != nil {
|
||||||
|
// we could not fetch the remote actor so we return our local cached copy
|
||||||
|
return e.JSON(http.StatusOK, map[string]any{"actor": actor, "error": err.Error()})
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.JSON(http.StatusOK, map[string]any{"actor": actor, "error": nil})
|
||||||
|
})
|
||||||
|
se.Router.GET("/activitypub/trail/{id}", func(e *core.RequestEvent) error {
|
||||||
|
id := e.Request.PathValue("id")
|
||||||
|
|
||||||
|
trail, err := e.App.FindRecordById("trails", id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
trailObject, err := util.ObjectFromTrail(e.App, trail, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.JSON(http.StatusOK, trailObject)
|
||||||
|
})
|
||||||
|
se.Router.GET("/activitypub/comment/{id}", func(e *core.RequestEvent) error {
|
||||||
|
id := e.Request.PathValue("id")
|
||||||
|
|
||||||
|
comment, err := e.App.FindRecordById("comments", id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
commentObject, err := util.ObjectFromComment(e.App, comment, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.JSON(http.StatusOK, commentObject)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerCronJobs(app core.App) {
|
func registerCronJobs(app core.App) {
|
||||||
@@ -818,7 +1115,7 @@ func registerCronJobs(app core.App) {
|
|||||||
|
|
||||||
func bootstrapData(app core.App, client meilisearch.ServiceManager) error {
|
func bootstrapData(app core.App, client meilisearch.ServiceManager) error {
|
||||||
bootstrapCategories(app)
|
bootstrapCategories(app)
|
||||||
bootstrapMeilisearchTrails(app, client)
|
go bootstrapMeilisearchDocuments(app, client)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -847,7 +1144,7 @@ func bootstrapCategories(app core.App) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bootstrapMeilisearchTrails(app core.App, client meilisearch.ServiceManager) error {
|
func bootstrapMeilisearchDocuments(app core.App, client meilisearch.ServiceManager) error {
|
||||||
query := app.RecordQuery("trails")
|
query := app.RecordQuery("trails")
|
||||||
trails := []*core.Record{}
|
trails := []*core.Record{}
|
||||||
|
|
||||||
@@ -860,7 +1157,7 @@ func bootstrapMeilisearchTrails(app core.App, client meilisearch.ServiceManager)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, trail := range trails {
|
for _, trail := range trails {
|
||||||
author, err := app.FindRecordById("users", trail.GetString(("author")))
|
author, err := app.FindRecordById("activitypub_actors", trail.GetString(("author")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -875,16 +1172,67 @@ func bootstrapMeilisearchTrails(app core.App, client meilisearch.ServiceManager)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
userIds := make([]string, len(shares))
|
actorIds := make([]string, len(shares))
|
||||||
for i, r := range shares {
|
for i, r := range shares {
|
||||||
userIds[i] = r.GetString("user")
|
actorIds[i] = r.GetString("actor")
|
||||||
}
|
}
|
||||||
err = util.UpdateTrailShares(trail.Id, userIds, client)
|
err = util.UpdateTrailShares(trail.Id, actorIds, client)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.Logger().Warn(fmt.Sprintf("Unable to update trail shares '%s': %v", trail.GetString("name"), err))
|
app.Logger().Warn(fmt.Sprintf("Unable to update trail shares '%s': %v", trail.GetString("name"), err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
likes, err := app.FindAllRecords("trail_like",
|
||||||
|
dbx.NewExp("trail = {:trailId}", dbx.Params{"trailId": trail.Id}),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
actorIds = make([]string, len(likes))
|
||||||
|
for i, r := range likes {
|
||||||
|
actorIds[i] = r.GetString("actor")
|
||||||
|
}
|
||||||
|
err = util.UpdateTrailLikes(trail.Id, actorIds, client)
|
||||||
|
if err != nil {
|
||||||
|
app.Logger().Warn(fmt.Sprintf("Unable to update trail likes '%s': %v", trail.GetString("name"), err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lists, err := app.FindAllRecords("lists")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = client.Index("lists").DeleteAllDocuments()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, list := range lists {
|
||||||
|
author, err := app.FindRecordById("activitypub_actors", list.GetString(("author")))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := util.IndexList(app, list, author, client); err != nil {
|
||||||
|
app.Logger().Warn(fmt.Sprintf("Unable to index list '%s': %v", list.GetString("name"), err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
shares, err := app.FindAllRecords("list_share",
|
||||||
|
dbx.NewExp("list = {:listId}", dbx.Params{"listId": list.Id}),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
actorIds := make([]string, len(shares))
|
||||||
|
for i, r := range shares {
|
||||||
|
actorIds[i] = r.GetString("actor")
|
||||||
|
}
|
||||||
|
err = util.UpdateListShares(list.Id, actorIds, client)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
app.Logger().Warn(fmt.Sprintf("Unable to update list shares '%s': %v", list.GetString("name"), err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
102
db/migrations/1747061255_deleted_follow_counts.go
Normal file
102
db/migrations/1747061255_deleted_follow_counts.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("j6w72f0kb5ivd7x")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Delete(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
jsonData := `{
|
||||||
|
"createRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text3208210256",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "id",
|
||||||
|
"pattern": "^[a-z0-9]+$",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": true,
|
||||||
|
"required": true,
|
||||||
|
"system": true,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cascadeDelete": false,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation1148540665",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "actor",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "_clone_kce8",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2215181735",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "followers",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json1908379107",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "following",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "j6w72f0kb5ivd7x",
|
||||||
|
"indexes": [],
|
||||||
|
"listRule": "@request.auth.id = user || (@collection.users_anonymous.id ?= user && @collection.users_anonymous.private ?= false)",
|
||||||
|
"name": "follow_counts",
|
||||||
|
"system": false,
|
||||||
|
"type": "view",
|
||||||
|
"updateRule": null,
|
||||||
|
"viewQuery": "SELECT \n (ROW_NUMBER() OVER()) as id,\n activitypub_actors.id as actor,\n activitypub_actors.user as user,\n COALESCE(followers.count, 0) AS followers,\n COALESCE(following.count, 0) AS following\nFROM activitypub_actors\nLEFT JOIN (\n SELECT followee AS actor_id, COUNT(*) AS count\n FROM follows\n GROUP BY followee\n) AS followers ON activitypub_actors.id = followers.actor_id\nLEFT JOIN (\n SELECT follower AS actor_id, COUNT(*) AS count\n FROM follows\n GROUP BY follower\n) AS following ON activitypub_actors.id = following.actor_id",
|
||||||
|
"viewRule": "@request.auth.id = user || (@collection.users_anonymous.id ?= user && @collection.users_anonymous.private ?= false)"
|
||||||
|
}`
|
||||||
|
|
||||||
|
collection := &core.Collection{}
|
||||||
|
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
186
db/migrations/1747061256_deleted_activities.go
Normal file
186
db/migrations/1747061256_deleted_activities.go
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("t9lphichi5xwyeu")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Delete(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
jsonData := `{
|
||||||
|
"createRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text3208210256",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "id",
|
||||||
|
"pattern": "^[a-z0-9]+$",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": true,
|
||||||
|
"required": true,
|
||||||
|
"system": true,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2310347867",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "trail_id",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2862495610",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "date",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json1579384326",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "name",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json1843675174",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "description",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3275261007",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "gpx",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3182418120",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json142008537",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "photos",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json479369857",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "distance",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2254405824",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "duration",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3015100073",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "elevation_gain",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3171089056",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "elevation_loss",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2990389176",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "created",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2363381545",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "type",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "t9lphichi5xwyeu",
|
||||||
|
"indexes": [],
|
||||||
|
"listRule": "(@collection.users_anonymous.id ?= author && @collection.users_anonymous.private ?= false\n&&\n@collection.trails.id ?= trail_id && \n (\n @collection.trails.author ?= @request.auth.id ||\n @collection.trails.public ?= true || \n (@request.auth.id != \"\" && @collection.trails.trail_share_via_trail.user ?= @request.auth.id)\n )) && @request.auth.id = author",
|
||||||
|
"name": "activities",
|
||||||
|
"system": false,
|
||||||
|
"type": "view",
|
||||||
|
"updateRule": null,
|
||||||
|
"viewQuery": "SELECT id,trail_id,date,name,description,gpx,author,photos,distance,duration,elevation_gain,elevation_loss,created,type \nFROM (\n SELECT summit_logs.id,trails.id as trail_id,summit_logs.date,trails.name,text as description,summit_logs.gpx,summit_logs.author,summit_logs.photos,summit_logs.distance,summit_logs.duration,summit_logs.elevation_gain,summit_logs.elevation_loss,summit_logs.created,\"summit_log\" as type \n FROM summit_logs\n JOIN trails ON summit_logs.id IN (\n SELECT value\n FROM json_each(trails.summit_logs)\n )\n UNION\n SELECT id,id as trail_id,date,name,description,gpx,author,photos,distance,duration,elevation_gain,elevation_loss,created,\"trail\" as type \n FROM trails\n)\nORDER BY created DESC",
|
||||||
|
"viewRule": "(@collection.users_anonymous.id ?= author && @collection.users_anonymous.private ?= false\n&&\n@collection.trails.id ?= trail_id && \n (\n @collection.trails.author ?= @request.auth.id ||\n @collection.trails.public ?= true || \n (@request.auth.id != \"\" && @collection.trails.trail_share_via_trail.user ?= @request.auth.id)\n )) && @request.auth.id = author"
|
||||||
|
}`
|
||||||
|
|
||||||
|
collection := &core.Collection{}
|
||||||
|
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
285
db/migrations/1747061257_created_activitypub_actors.go
Normal file
285
db/migrations/1747061257_created_activitypub_actors.go
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
jsonData := `[
|
||||||
|
{
|
||||||
|
"id": "pbc_1295301207",
|
||||||
|
"listRule": "",
|
||||||
|
"viewRule": "",
|
||||||
|
"createRule": null,
|
||||||
|
"updateRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"name": "activitypub_actors",
|
||||||
|
"type": "base",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "[a-z0-9]{15}",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text3208210256",
|
||||||
|
"max": 15,
|
||||||
|
"min": 15,
|
||||||
|
"name": "id",
|
||||||
|
"pattern": "^[a-z0-9]+$",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": true,
|
||||||
|
"required": true,
|
||||||
|
"system": true,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text4166911607",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "username",
|
||||||
|
"pattern": "",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text4002953752",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "preferred_username",
|
||||||
|
"pattern": "",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text2812878347",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "domain",
|
||||||
|
"pattern": "",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text3458754147",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "summary",
|
||||||
|
"pattern": "",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "number1386272118",
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"name": "followerCount",
|
||||||
|
"onlyInt": true,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "number3430500629",
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"name": "followingCount",
|
||||||
|
"onlyInt": true,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "date1748787223",
|
||||||
|
"max": "",
|
||||||
|
"min": "",
|
||||||
|
"name": "published",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptDomains": null,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url126331327",
|
||||||
|
"name": "iri",
|
||||||
|
"onlyDomains": null,
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptDomains": null,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url2115105593",
|
||||||
|
"name": "inbox",
|
||||||
|
"onlyDomains": null,
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptDomains": null,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url1793578352",
|
||||||
|
"name": "outbox",
|
||||||
|
"onlyDomains": null,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptDomains": null,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url1704208859",
|
||||||
|
"name": "icon",
|
||||||
|
"onlyDomains": null,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptDomains": null,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url2215181735",
|
||||||
|
"name": "followers",
|
||||||
|
"onlyDomains": null,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptDomains": null,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url1908379107",
|
||||||
|
"name": "following",
|
||||||
|
"onlyDomains": null,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "bool2193750486",
|
||||||
|
"name": "isLocal",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text1727648867",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "public_key",
|
||||||
|
"pattern": "",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": true,
|
||||||
|
"id": "text4160324774",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "private_key",
|
||||||
|
"pattern": "",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation2375276105",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "date2062531289",
|
||||||
|
"max": "",
|
||||||
|
"min": "",
|
||||||
|
"name": "last_fetched",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "autodate2990389176",
|
||||||
|
"name": "created",
|
||||||
|
"onCreate": true,
|
||||||
|
"onUpdate": false,
|
||||||
|
"presentable": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "autodate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "autodate3332085495",
|
||||||
|
"name": "updated",
|
||||||
|
"onCreate": true,
|
||||||
|
"onUpdate": true,
|
||||||
|
"presentable": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "autodate"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
"CREATE UNIQUE INDEX ` + "`idx_rpT7QJwWTm` ON `activitypub_actors` (`iri`)" + `"
|
||||||
|
],
|
||||||
|
"system": false
|
||||||
|
}
|
||||||
|
]`
|
||||||
|
|
||||||
|
return app.ImportCollectionsByMarshaledJSON([]byte(jsonData), false)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
156
db/migrations/1747061258_created_activitypub_activities.go
Normal file
156
db/migrations/1747061258_created_activitypub_activities.go
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
jsonData := `[
|
||||||
|
{
|
||||||
|
"id": "pbc_3752774184",
|
||||||
|
"listRule": "",
|
||||||
|
"viewRule": "",
|
||||||
|
"createRule": null,
|
||||||
|
"updateRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"name": "activitypub_activities",
|
||||||
|
"type": "base",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "[a-z0-9]{15}",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text3208210256",
|
||||||
|
"max": 15,
|
||||||
|
"min": 15,
|
||||||
|
"name": "id",
|
||||||
|
"pattern": "^[a-z0-9]+$",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": true,
|
||||||
|
"required": true,
|
||||||
|
"system": true,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptDomains": [],
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url2434853685",
|
||||||
|
"name": "iri",
|
||||||
|
"onlyDomains": [],
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text2363381545",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "type",
|
||||||
|
"pattern": "",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3616002756",
|
||||||
|
"maxSize": 0,
|
||||||
|
"name": "to",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3685882489",
|
||||||
|
"maxSize": 0,
|
||||||
|
"name": "cc",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2893285722",
|
||||||
|
"maxSize": 0,
|
||||||
|
"name": "object",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exceptDomains": [],
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url1148540665",
|
||||||
|
"name": "actor",
|
||||||
|
"onlyDomains": [],
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "date1748787223",
|
||||||
|
"max": "",
|
||||||
|
"min": "",
|
||||||
|
"name": "published",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text1653163849",
|
||||||
|
"max": 15,
|
||||||
|
"min": 15,
|
||||||
|
"name": "relation",
|
||||||
|
"pattern": "^[a-z0-9]+$",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "autodate2990389176",
|
||||||
|
"name": "created",
|
||||||
|
"onCreate": true,
|
||||||
|
"onUpdate": false,
|
||||||
|
"presentable": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "autodate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "autodate3332085495",
|
||||||
|
"name": "updated",
|
||||||
|
"onCreate": true,
|
||||||
|
"onUpdate": true,
|
||||||
|
"presentable": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "autodate"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"indexes": [],
|
||||||
|
"system": false
|
||||||
|
}
|
||||||
|
]`
|
||||||
|
|
||||||
|
return app.ImportCollectionsByMarshaledJSON([]byte(jsonData), false)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
30
db/migrations/1747061259_seed_actors.go
Normal file
30
db/migrations/1747061259_seed_actors.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"pocketbase/util"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
users, err := app.FindAllRecords("users")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, u := range users {
|
||||||
|
_, err = util.ActorFromUser(app, u)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
// add down queries...
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
78
db/migrations/1747061260_trails_add_new_author.go
Normal file
78
db/migrations/1747061260_trails_add_new_author.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(15, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation3182418120",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(16, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "1utgul91",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation3182418120")
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(15, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "1utgul91",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
33
db/migrations/1747061261_set_trail_authors.go
Normal file
33
db/migrations/1747061261_set_trail_authors.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
trails, err := app.FindAllRecords("trails")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range trails {
|
||||||
|
actor, err := app.FindFirstRecordByData("activitypub_actors", "user", t.GetString("user"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.Set("author", actor.Id)
|
||||||
|
err = app.UnsafeWithoutHooks().Save(t)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
// add down queries...
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
78
db/migrations/1747061262_comments_add_new_author.go
Normal file
78
db/migrations/1747061262_comments_add_new_author.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("comments")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(3, []byte(`{
|
||||||
|
"cascadeDelete": false,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation3182418120",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(16, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "7lwo1mxx",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("comments")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation3182418120")
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(15, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "7lwo1mxx",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
33
db/migrations/1747061263_set_comment_authors.go
Normal file
33
db/migrations/1747061263_set_comment_authors.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
comments, err := app.FindAllRecords("comments")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range comments {
|
||||||
|
actor, err := app.FindFirstRecordByData("activitypub_actors", "user", c.GetString("user"))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.Set("author", actor.Id)
|
||||||
|
err = app.UnsafeWithoutHooks().Save(c)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
// add down queries...
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
78
db/migrations/1747061264_summit_logs_add_new_author.go
Normal file
78
db/migrations/1747061264_summit_logs_add_new_author.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("summit_logs")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(9, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation3182418120",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(16, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "r0mj3tkr",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("summit_logs")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation3182418120")
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(15, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "r0mj3tkr",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
46
db/migrations/1747061265_set_summit_log_authors.go
Normal file
46
db/migrations/1747061265_set_summit_log_authors.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
logs, err := app.FindAllRecords("summit_logs")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, l := range logs {
|
||||||
|
if l.GetString("user") == "" {
|
||||||
|
trail, err := app.FindFirstRecordByFilter("trails", "summit_logs ?~ {:id}", dbx.Params{"id": l.Id})
|
||||||
|
if err != nil {
|
||||||
|
// orphaned
|
||||||
|
err = app.UnsafeWithoutHooks().Delete(l)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l.Set("user", trail.GetString("user"))
|
||||||
|
}
|
||||||
|
actor, err := app.FindFirstRecordByData("activitypub_actors", "user", l.GetString("user"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
l.Set("author", actor.Id)
|
||||||
|
err = app.UnsafeWithoutHooks().Save(l)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
// add down queries...
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
55
db/migrations/1747061266_migrate_ms_token.go
Normal file
55
db/migrations/1747061266_migrate_ms_token.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"pocketbase/util"
|
||||||
|
|
||||||
|
"github.com/meilisearch/meilisearch-go"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
client := meilisearch.New(os.Getenv("MEILI_URL"), meilisearch.WithAPIKey(os.Getenv("MEILI_MASTER_KEY")))
|
||||||
|
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
|
||||||
|
users, err := app.FindAllRecords("users")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, u := range users {
|
||||||
|
userId := u.Id
|
||||||
|
|
||||||
|
actor, err := app.FindFirstRecordByData("activitypub_actors", "user", userId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
searchRules := map[string]interface{}{
|
||||||
|
"lists": map[string]string{
|
||||||
|
"filter": "public = true OR author = " + actor.Id + " OR shares = " + userId,
|
||||||
|
},
|
||||||
|
"trails": map[string]string{
|
||||||
|
"filter": "public = true OR author = " + actor.Id + " OR shares = " + userId,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := util.GenerateMeilisearchToken(searchRules, client)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u.Set("token", token)
|
||||||
|
if err := app.Save(u); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
// add down queries...
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1747061267_summit_logs_add_trail_field.go
Normal file
44
db/migrations/1747061267_summit_logs_add_trail_field.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(10, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "e864strfxo14pm4",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation2993194383",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "trail",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation2993194383")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
34
db/migrations/1747061268_migrate_summit_log_trails.go
Normal file
34
db/migrations/1747061268_migrate_summit_log_trails.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
logs, err := app.FindAllRecords("summit_logs")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, l := range logs {
|
||||||
|
trail, err := app.FindFirstRecordByFilter("trails", "summit_logs ?~ {:id}", dbx.Params{"id": l.Id})
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l.Set("trail", trail.Id)
|
||||||
|
err = app.UnsafeWithoutHooks().Save(l)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
// add down queries...
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1747061269_trails_remove_summit_log_field.go
Normal file
44
db/migrations/1747061269_trails_remove_summit_log_field.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("e1lwowvd")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(17, []byte(`{
|
||||||
|
"cascadeDelete": false,
|
||||||
|
"collectionId": "dd2l9a4vxpy2ni8",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "e1lwowvd",
|
||||||
|
"maxSelect": 2147483647,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "summit_logs",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
150
db/migrations/1747061270_follows_add_new_f_f.go
Normal file
150
db/migrations/1747061270_follows_add_new_f_f.go
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("8obn1ukumze565i")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "in1traur",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "old_follower",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "wxwomfd5",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "old_followee",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(3, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "select2063623452",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"name": "status",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "select",
|
||||||
|
"values": [
|
||||||
|
"pending",
|
||||||
|
"accepted"
|
||||||
|
]
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation3117812038",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "follower",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation973442177",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "followee",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("8obn1ukumze565i")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "in1traur",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "follower",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "wxwomfd5",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "followee",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation3117812038")
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation973442177")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
60
db/migrations/1747061271_migrate_follows.go
Normal file
60
db/migrations/1747061271_migrate_follows.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
follows, err := app.FindAllRecords("follows")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
seen := map[string]string{}
|
||||||
|
for _, f := range follows {
|
||||||
|
oldFollower := f.GetString("old_follower")
|
||||||
|
oldFollowee := f.GetString("old_followee")
|
||||||
|
|
||||||
|
if oldFollowee == "" || oldFollower == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
seenFollowee, ok := seen[oldFollower]
|
||||||
|
if ok && seenFollowee == oldFollowee {
|
||||||
|
err = app.Delete(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[oldFollower] = oldFollowee
|
||||||
|
|
||||||
|
followerActor, err := app.FindFirstRecordByData("activitypub_actors", "user", oldFollower)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
followeeActor, err := app.FindFirstRecordByData("activitypub_actors", "user", oldFollowee)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Set("follower", followerActor.Id)
|
||||||
|
f.Set("followee", followeeActor.Id)
|
||||||
|
f.Set("status", "accepted")
|
||||||
|
|
||||||
|
err = app.UnsafeWithoutHooks().Save(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
// add down queries...
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
1159
db/migrations/1747064968_collections_snapshot.go
Normal file
1159
db/migrations/1747064968_collections_snapshot.go
Normal file
File diff suppressed because it is too large
Load Diff
44
db/migrations/1747066702_updated_comments.go
Normal file
44
db/migrations/1747066702_updated_comments.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lf06qip3f4d11yk")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("7lwo1mxx")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lf06qip3f4d11yk")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(6, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "7lwo1mxx",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1747066720_updated_summit_logs.go
Normal file
44
db/migrations/1747066720_updated_summit_logs.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("r0mj3tkr")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(13, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "r0mj3tkr",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1747066741_updated_trails.go
Normal file
44
db/migrations/1747066741_updated_trails.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("1utgul91")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(24, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "1utgul91",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
26
db/migrations/1747066742_updated_follows.go
Normal file
26
db/migrations/1747066742_updated_follows.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("8obn1ukumze565i")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// // remove field
|
||||||
|
collection.Fields.RemoveById("in1traur")
|
||||||
|
|
||||||
|
// // remove field
|
||||||
|
collection.Fields.RemoveById("wxwomfd5")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
|
||||||
|
}, func(app core.App) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
186
db/migrations/1747236775_created_timeline.go
Normal file
186
db/migrations/1747236775_created_timeline.go
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
jsonData := `{
|
||||||
|
"createRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text3208210256",
|
||||||
|
"max": 0,
|
||||||
|
"min": 0,
|
||||||
|
"name": "id",
|
||||||
|
"pattern": "^[a-z0-9]+$",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": true,
|
||||||
|
"required": true,
|
||||||
|
"system": true,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2310347867",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "trail_id",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2862495610",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "date",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json1579384326",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "name",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json1843675174",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "description",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3275261007",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "gpx",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3182418120",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json142008537",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "photos",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json479369857",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "distance",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2254405824",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "duration",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3015100073",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "elevation_gain",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3171089056",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "elevation_loss",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2990389176",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "created",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2363381545",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "type",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "pbc_468398817",
|
||||||
|
"indexes": [],
|
||||||
|
"listRule": "@collection.trails.id ?= trail_id && @collection.trails.public ?= true",
|
||||||
|
"name": "timeline",
|
||||||
|
"system": false,
|
||||||
|
"type": "view",
|
||||||
|
"updateRule": null,
|
||||||
|
"viewQuery": "-- database: /Users/christianbeutel/Documents/svelte/wanderer/db/pb_data/data.db\nSELECT\n (ROW_NUMBER() OVER ()) as id,\n trail_id,\n date,\n name,\n description,\n gpx,\n author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n created,\n type\nFROM\n (\n SELECT\n summit_logs.trail as trail_id,\n summit_logs.date,\n trails.name,\n text as description,\n summit_logs.gpx,\n activitypub_actors.iri as author,\n summit_logs.photos,\n summit_logs.distance,\n summit_logs.duration,\n summit_logs.elevation_gain,\n summit_logs.elevation_loss,\n summit_logs.created,\n \"summit_log\" as type\n FROM\n summit_logs\n JOIN trails ON summit_logs.trail = trails.id\n JOIN activitypub_actors ON activitypub_actors.id = summit_logs.author\n UNION\n SELECT\n trails.id as trail_id,\n date,\n trails.name,\n description,\n gpx,\n activitypub_actors.iri as author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n trails.created,\n \"trail\" as type\n FROM\n trails\n JOIN activitypub_actors ON activitypub_actors.id = trails.author\n )\nORDER BY\n created DESC;\n",
|
||||||
|
"viewRule": "@collection.trails.id ?= trail_id && @collection.trails.public ?= true"
|
||||||
|
}`
|
||||||
|
|
||||||
|
collection := &core.Collection{}
|
||||||
|
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_468398817")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Delete(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
40
db/migrations/1747242599_updated_timeline.go
Normal file
40
db/migrations/1747242599_updated_timeline.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_468398817")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT\n (ROW_NUMBER() OVER ()) as id,\n trail_id,\n date,\n name,\n description,\n gpx,\n author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n created,\n type\nFROM\n (\n SELECT\n summit_logs.trail as trail_id,\n summit_logs.date,\n trails.name,\n text as description,\n summit_logs.gpx,\n activitypub_actors.iri as author,\n summit_logs.photos,\n summit_logs.distance,\n summit_logs.duration,\n summit_logs.elevation_gain,\n summit_logs.elevation_loss,\n summit_logs.created,\n \"summit_log\" as type\n FROM\n summit_logs\n JOIN trails ON summit_logs.trail = trails.id\n JOIN activitypub_actors ON activitypub_actors.id = summit_logs.author\n UNION\n SELECT\n trails.id as trail_id,\n date,\n trails.name,\n description,\n gpx,\n activitypub_actors.iri as author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n trails.created,\n \"trail\" as type\n FROM\n trails\n JOIN activitypub_actors ON activitypub_actors.id = trails.author\n )\nORDER BY\n created DESC;\n"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_468398817")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "-- database: /Users/christianbeutel/Documents/svelte/wanderer/db/pb_data/data.db\nSELECT\n (ROW_NUMBER() OVER ()) as id,\n trail_id,\n date,\n name,\n description,\n gpx,\n author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n created,\n type\nFROM\n (\n SELECT\n summit_logs.trail as trail_id,\n summit_logs.date,\n trails.name,\n text as description,\n summit_logs.gpx,\n activitypub_actors.iri as author,\n summit_logs.photos,\n summit_logs.distance,\n summit_logs.duration,\n summit_logs.elevation_gain,\n summit_logs.elevation_loss,\n summit_logs.created,\n \"summit_log\" as type\n FROM\n summit_logs\n JOIN trails ON summit_logs.trail = trails.id\n JOIN activitypub_actors ON activitypub_actors.id = summit_logs.author\n UNION\n SELECT\n trails.id as trail_id,\n date,\n trails.name,\n description,\n gpx,\n activitypub_actors.iri as author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n trails.created,\n \"trail\" as type\n FROM\n trails\n JOIN activitypub_actors ON activitypub_actors.id = trails.author\n )\nORDER BY\n created DESC;\n"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
40
db/migrations/1747300536_updated_timeline.go
Normal file
40
db/migrations/1747300536_updated_timeline.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_468398817")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT\n id,\n trail_id,\n date,\n name,\n description,\n gpx,\n author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n created,\n type\nFROM\n (\n SELECT\n summit_logs.id,\n summit_logs.trail as trail_id,\n summit_logs.date,\n trails.name,\n text as description,\n summit_logs.gpx,\n activitypub_actors.iri as author,\n summit_logs.photos,\n summit_logs.distance,\n summit_logs.duration,\n summit_logs.elevation_gain,\n summit_logs.elevation_loss,\n summit_logs.created,\n \"summit_log\" as type\n FROM\n summit_logs\n JOIN trails ON summit_logs.trail = trails.id\n JOIN activitypub_actors ON activitypub_actors.id = summit_logs.author\n UNION\n SELECT\n trails.id,\n trails.id as trail_id,\n date,\n trails.name,\n description,\n gpx,\n activitypub_actors.iri as author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n trails.created,\n \"trail\" as type\n FROM\n trails\n JOIN activitypub_actors ON activitypub_actors.id = trails.author\n )\nORDER BY\n created DESC;\n"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_468398817")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT\n (ROW_NUMBER() OVER ()) as id,\n trail_id,\n date,\n name,\n description,\n gpx,\n author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n created,\n type\nFROM\n (\n SELECT\n summit_logs.trail as trail_id,\n summit_logs.date,\n trails.name,\n text as description,\n summit_logs.gpx,\n activitypub_actors.iri as author,\n summit_logs.photos,\n summit_logs.distance,\n summit_logs.duration,\n summit_logs.elevation_gain,\n summit_logs.elevation_loss,\n summit_logs.created,\n \"summit_log\" as type\n FROM\n summit_logs\n JOIN trails ON summit_logs.trail = trails.id\n JOIN activitypub_actors ON activitypub_actors.id = summit_logs.author\n UNION\n SELECT\n trails.id as trail_id,\n date,\n trails.name,\n description,\n gpx,\n activitypub_actors.iri as author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n trails.created,\n \"trail\" as type\n FROM\n trails\n JOIN activitypub_actors ON activitypub_actors.id = trails.author\n )\nORDER BY\n created DESC;\n"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
43
db/migrations/1747312289_updated_comments.go
Normal file
43
db/migrations/1747312289_updated_comments.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lf06qip3f4d11yk")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("fhgxdiam")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lf06qip3f4d11yk")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(6, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "fhgxdiam",
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"name": "rating",
|
||||||
|
"onlyInt": false,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "number"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1747381400_updated_trails.go
Normal file
42
db/migrations/1747381400_updated_trails.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(22, []byte(`{
|
||||||
|
"exceptDomains": [],
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url1760183548",
|
||||||
|
"name": "iri",
|
||||||
|
"onlyDomains": [],
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("url1760183548")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
40
db/migrations/1747382660_updated_trails.go
Normal file
40
db/migrations/1747382660_updated_trails.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (@request.body.author.user = @request.auth.id || author.isLocal = false)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (@request.body.author.user = @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
40
db/migrations/1747383776_updated_trails.go
Normal file
40
db/migrations/1747383776_updated_trails.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"updateRule": "author.user = @request.auth.id || (@request.auth.id != \"\" && trail_share_via_trail.trail = id && trail_share_via_trail.user ?= @request.auth.id && trail_share_via_trail.permission = \"edit\") || (@request.auth.id != \"\" && author.isLocal = false)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"updateRule": "author.user = @request.auth.id || (@request.auth.id != \"\" && trail_share_via_trail.trail = id && trail_share_via_trail.user ?= @request.auth.id && trail_share_via_trail.permission = \"edit\")"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1747499980_updated_comments.go
Normal file
42
db/migrations/1747499980_updated_comments.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lf06qip3f4d11yk")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(4, []byte(`{
|
||||||
|
"exceptDomains": null,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url2434853685",
|
||||||
|
"name": "iri",
|
||||||
|
"onlyDomains": null,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lf06qip3f4d11yk")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("url2434853685")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1747554117_updated_summit_logs.go
Normal file
42
db/migrations/1747554117_updated_summit_logs.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(11, []byte(`{
|
||||||
|
"exceptDomains": null,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url2434853685",
|
||||||
|
"name": "iri",
|
||||||
|
"onlyDomains": null,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("url2434853685")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
40
db/migrations/1747554570_updated_summit_logs.go
Normal file
40
db/migrations/1747554570_updated_summit_logs.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (trail.author.user = @request.auth.id || trail.public = true)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\""
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
78
db/migrations/1747674856_updated_lists.go
Normal file
78
db/migrations/1747674856_updated_lists.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(5, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation3182418120",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(6, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "kwm6zdet",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation3182418120")
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(5, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "kwm6zdet",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
33
db/migrations/1747674913_set_list_authors.go
Normal file
33
db/migrations/1747674913_set_list_authors.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
lists, err := app.FindAllRecords("lists")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, l := range lists {
|
||||||
|
actor, err := app.FindFirstRecordByData("activitypub_actors", "user", l.GetString("user"))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l.Set("author", actor.Id)
|
||||||
|
err = app.UnsafeWithoutHooks().Save(l)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
// add down queries...
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1747675001_updated_lists.go
Normal file
44
db/migrations/1747675001_updated_lists.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("kwm6zdet")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(6, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "kwm6zdet",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
48
db/migrations/1747676287_updated_lists.go
Normal file
48
db/migrations/1747676287_updated_lists.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (@request.body.author.user = @request.auth.id)",
|
||||||
|
"deleteRule": "author.user = @request.auth.id ",
|
||||||
|
"listRule": "author.user = @request.auth.id || public = true || (@request.auth.id != \"\" && list_share_via_list.user ?= @request.auth.id)",
|
||||||
|
"updateRule": "author.user = @request.auth.id || (@request.auth.id != \"\" && list_share_via_list.list = id && list_share_via_list.user ?= @request.auth.id && list_share_via_list.permission = \"edit\")",
|
||||||
|
"viewRule": "author.user = @request.auth.id || public = true || (@request.auth.id != \"\" && list_share_via_list.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (@request.body.author = @request.auth.id)",
|
||||||
|
"deleteRule": "author = @request.auth.id ",
|
||||||
|
"listRule": "author = @request.auth.id || public = true || (@request.auth.id != \"\" && list_share_via_list.user ?= @request.auth.id)",
|
||||||
|
"updateRule": "author = @request.auth.id || (@request.auth.id != \"\" && list_share_via_list.list = id && list_share_via_list.user ?= @request.auth.id && list_share_via_list.permission = \"edit\")",
|
||||||
|
"viewRule": "author = @request.auth.id || public = true || (@request.auth.id != \"\" && list_share_via_list.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1747683009_updated_lists.go
Normal file
42
db/migrations/1747683009_updated_lists.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(7, []byte(`{
|
||||||
|
"exceptDomains": null,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "url2434853685",
|
||||||
|
"name": "iri",
|
||||||
|
"onlyDomains": null,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "url"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("url2434853685")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
40
db/migrations/1747683368_updated_lists.go
Normal file
40
db/migrations/1747683368_updated_lists.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (@request.body.author.user = @request.auth.id || author.isLocal = false)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (@request.body.author.user = @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
40
db/migrations/1747683707_updated_lists.go
Normal file
40
db/migrations/1747683707_updated_lists.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"updateRule": "author.user = @request.auth.id || (@request.auth.id != \"\" && list_share_via_list.list = id && list_share_via_list.user ?= @request.auth.id && list_share_via_list.permission = \"edit\") || (@request.auth.id != \"\" && author.isLocal = false)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"updateRule": "author.user = @request.auth.id || (@request.auth.id != \"\" && list_share_via_list.list = id && list_share_via_list.user ?= @request.auth.id && list_share_via_list.permission = \"edit\")"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
57
db/migrations/1747945195_updated_timeline.go
Normal file
57
db/migrations/1747945195_updated_timeline.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_468398817")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT\n id,\n trail_id,\n iri,\n date,\n name,\n description,\n gpx,\n author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n created,\n type\nFROM\n (\n SELECT\n summit_logs.id,\n summit_logs.trail as trail_id,\n trails.iri,\n summit_logs.date,\n trails.name,\n text as description,\n summit_logs.gpx,\n activitypub_actors.iri as author,\n summit_logs.photos,\n summit_logs.distance,\n summit_logs.duration,\n summit_logs.elevation_gain,\n summit_logs.elevation_loss,\n summit_logs.created,\n \"summit_log\" as type\n FROM\n summit_logs\n JOIN trails ON summit_logs.trail = trails.id\n JOIN activitypub_actors ON activitypub_actors.id = summit_logs.author\n UNION\n SELECT\n trails.id,\n trails.id as trail_id,\n trails.iri,\n date,\n trails.name,\n description,\n gpx,\n activitypub_actors.iri as author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n trails.created,\n \"trail\" as type\n FROM\n trails\n JOIN activitypub_actors ON activitypub_actors.id = trails.author\n )\nORDER BY\n created DESC;\n"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2434853685",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "iri",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_468398817")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT\n id,\n trail_id,\n date,\n name,\n description,\n gpx,\n author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n created,\n type\nFROM\n (\n SELECT\n summit_logs.id,\n summit_logs.trail as trail_id,\n summit_logs.date,\n trails.name,\n text as description,\n summit_logs.gpx,\n activitypub_actors.iri as author,\n summit_logs.photos,\n summit_logs.distance,\n summit_logs.duration,\n summit_logs.elevation_gain,\n summit_logs.elevation_loss,\n summit_logs.created,\n \"summit_log\" as type\n FROM\n summit_logs\n JOIN trails ON summit_logs.trail = trails.id\n JOIN activitypub_actors ON activitypub_actors.id = summit_logs.author\n UNION\n SELECT\n trails.id,\n trails.id as trail_id,\n date,\n trails.name,\n description,\n gpx,\n activitypub_actors.iri as author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n trails.created,\n \"trail\" as type\n FROM\n trails\n JOIN activitypub_actors ON activitypub_actors.id = trails.author\n )\nORDER BY\n created DESC;\n"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("json2434853685")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1747946749_updated_trails.go
Normal file
42
db/migrations/1747946749_updated_trails.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": [
|
||||||
|
"CREATE INDEX ` + "`" + `idx_6tD5RqfVk2` + "`" + ` ON ` + "`" + `trails` + "`" + ` (` + "`" + `iri` + "`" + `)"
|
||||||
|
]
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": []
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1747946778_updated_lists.go
Normal file
42
db/migrations/1747946778_updated_lists.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": [
|
||||||
|
"CREATE INDEX ` + "`" + `idx_hLtEU5XGWL` + "`" + ` ON ` + "`" + `lists` + "`" + ` (` + "`" + `iri` + "`" + `)"
|
||||||
|
]
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": []
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
108
db/migrations/1747952550_updated_timeline.go
Normal file
108
db/migrations/1747952550_updated_timeline.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_468398817")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT\n id,\n trail_id,\n trail_author_username,\n trail_author_domain,\n trail_iri,\n date,\n name,\n description,\n gpx,\n author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n created,\n type\nFROM\n (\n SELECT\n summit_logs.id,\n summit_logs.trail as trail_id,\n tapa.username as trail_author_username,\n tapa.domain as trail_author_domain,\n trails.iri as trail_iri,\n summit_logs.date,\n trails.name,\n text as description,\n summit_logs.gpx,\n sapa.iri as author,\n summit_logs.photos,\n summit_logs.distance,\n summit_logs.duration,\n summit_logs.elevation_gain,\n summit_logs.elevation_loss,\n summit_logs.created,\n \"summit_log\" as type\n FROM\n summit_logs\n JOIN trails ON summit_logs.trail = trails.id\n JOIN activitypub_actors sapa ON sapa.id = summit_logs.author\n JOIN activitypub_actors tapa ON tapa.id = trails.author\n UNION\n SELECT\n trails.id,\n trails.id as trail_id,\n activitypub_actors.username as trail_author_username,\n activitypub_actors.domain as trail_author_domain,\n trails.iri as trail_iri,\n date,\n trails.name,\n description,\n gpx,\n activitypub_actors.iri as author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n trails.created,\n \"trail\" as type\n FROM\n trails\n JOIN activitypub_actors ON activitypub_actors.id = trails.author\n )\nORDER BY\n created DESC;\n"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("json2434853685")
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json3184124860",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "trail_author_username",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(3, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2887874732",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "trail_author_domain",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(4, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json113557190",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "trail_iri",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_468398817")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT\n id,\n trail_id,\n iri,\n date,\n name,\n description,\n gpx,\n author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n created,\n type\nFROM\n (\n SELECT\n summit_logs.id,\n summit_logs.trail as trail_id,\n trails.iri,\n summit_logs.date,\n trails.name,\n text as description,\n summit_logs.gpx,\n activitypub_actors.iri as author,\n summit_logs.photos,\n summit_logs.distance,\n summit_logs.duration,\n summit_logs.elevation_gain,\n summit_logs.elevation_loss,\n summit_logs.created,\n \"summit_log\" as type\n FROM\n summit_logs\n JOIN trails ON summit_logs.trail = trails.id\n JOIN activitypub_actors ON activitypub_actors.id = summit_logs.author\n UNION\n SELECT\n trails.id,\n trails.id as trail_id,\n trails.iri,\n date,\n trails.name,\n description,\n gpx,\n activitypub_actors.iri as author,\n photos,\n distance,\n duration,\n elevation_gain,\n elevation_loss,\n trails.created,\n \"trail\" as type\n FROM\n trails\n JOIN activitypub_actors ON activitypub_actors.id = trails.author\n )\nORDER BY\n created DESC;\n"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "json2434853685",
|
||||||
|
"maxSize": 1,
|
||||||
|
"name": "iri",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "json"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("json3184124860")
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("json2887874732")
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("json113557190")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
104
db/migrations/1747995473_updated_notifications.go
Normal file
104
db/migrations/1747995473_updated_notifications.go
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("tmghd4vo")
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("exqo1whj")
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(4, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation1745156937",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "recipient",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(5, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation3182418120",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(4, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "tmghd4vo",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "recipient",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(5, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "exqo1whj",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "author",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation1745156937")
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation3182418120")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1747996502_updated_notifications.go
Normal file
44
db/migrations/1747996502_updated_notifications.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "@request.auth.id = recipient.user",
|
||||||
|
"updateRule": "@request.auth.id = recipient.user && (@request.body.type = null||@request.body.type = type) && (@request.body.metadata = null||@request.body.metadata = metadata) && (@request.body.recipient = null||@request.body.recipient = recipient) && (@request.body.author = null||@request.body.author = author) && @request.body.seen = true",
|
||||||
|
"viewRule": "@request.auth.id = recipient.user"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "@request.auth.id = recipient",
|
||||||
|
"updateRule": "@request.auth.id = recipient && (@request.body.type = null||@request.body.type = type) && (@request.body.metadata = null||@request.body.metadata = metadata) && (@request.body.recipient = null||@request.body.recipient = recipient) && (@request.body.author = null||@request.body.author = author) && @request.body.seen = true",
|
||||||
|
"viewRule": "@request.auth.id = recipient"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
67
db/migrations/1747999298_updated_notifications.go
Normal file
67
db/migrations/1747999298_updated_notifications.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "b57prsbu",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"name": "type",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "select",
|
||||||
|
"values": [
|
||||||
|
"new_follower",
|
||||||
|
"trail_comment",
|
||||||
|
"trail_share",
|
||||||
|
"list_share",
|
||||||
|
"summit_log_create"
|
||||||
|
]
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "b57prsbu",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"name": "type",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "select",
|
||||||
|
"values": [
|
||||||
|
"trail_create",
|
||||||
|
"list_create",
|
||||||
|
"new_follower",
|
||||||
|
"trail_comment",
|
||||||
|
"trail_share",
|
||||||
|
"list_share"
|
||||||
|
]
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1748002661_updated_follows.go
Normal file
42
db/migrations/1748002661_updated_follows.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("8obn1ukumze565i")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": [
|
||||||
|
"CREATE UNIQUE INDEX `+"`"+`idx_oM5KTHL3Lf`+"`"+` ON `+"`"+`follows`+"`"+` (\n `+"`"+`follower`+"`"+`,\n `+"`"+`followee`+"`"+`\n)"
|
||||||
|
]
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("8obn1ukumze565i")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": []
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1748003743_updated_summit_logs.go
Normal file
42
db/migrations/1748003743_updated_summit_logs.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || (@collection.trail_share.trail ?= trail && @collection.trail_share.trail ?= @request.auth.id)",
|
||||||
|
"viewRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || (@collection.trail_share.trail ?= trail && @collection.trail_share.trail ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || \ntrail.trail_share_via_trail.user = @request.auth.id",
|
||||||
|
"viewRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || \ntrail.trail_share_via_trail.user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1748084027_updated_follows.go
Normal file
42
db/migrations/1748084027_updated_follows.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("8obn1ukumze565i")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "",
|
||||||
|
"viewRule": ""
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("8obn1ukumze565i")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "@request.auth.id = follower.user.id || @request.auth.id = followee.user.id",
|
||||||
|
"viewRule": "@request.auth.id = follower.user.id || @request.auth.id = followee.user.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1749553104_updated_trail_share.go
Normal file
44
db/migrations/1749553104_updated_trail_share.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("1mns8mlal6uf9ku")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation2375276105",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "actor",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("1mns8mlal6uf9ku")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation2375276105")
|
||||||
|
|
||||||
|
return app.UnsafeWithoutHooks().Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
31
db/migrations/1749553105_migrate_trail_share.go
Normal file
31
db/migrations/1749553105_migrate_trail_share.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
shares, err := app.FindAllRecords("trail_share")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range shares {
|
||||||
|
actor, err := app.FindFirstRecordByData("activitypub_actors", "user", s.GetString("user"))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.Set("actor", actor.Id)
|
||||||
|
err = app.Save(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
80
db/migrations/1749554811_updated_trails_filter.go
Normal file
80
db/migrations/1749554811_updated_trails_filter.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("4wbv9tz5zjdrjh1")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT activitypub_actors.id, activitypub_actors.user, COALESCE(printf(\"%.2f\", MAX(trails.distance)), 0) AS max_distance,\n COALESCE(printf(\"%.2f\", MAX(trails.elevation_gain)), 0) AS max_elevation_gain, \n COALESCE(printf(\"%.2f\", MAX(trails.elevation_loss)), 0) AS max_elevation_loss, \n COALESCE(printf(\"%.2f\", MAX(trails.duration)), 0) AS max_duration, \n COALESCE(printf(\"%.2f\", MIN(trails.distance)), 0) AS min_distance, \n COALESCE(printf(\"%.2f\", MIN(trails.elevation_gain)), 0) AS min_elevation_gain, \n COALESCE(printf(\"%.2f\", MIN(trails.elevation_loss)), 0) AS min_elevation_loss, \n COALESCE(printf(\"%.2f\", MIN(trails.duration)), 0) AS min_duration \nFROM activitypub_actors \n LEFT JOIN trails ON \n activitypub_actors.id = trails.author OR \n trails.public = 1 OR \n EXISTS (\n SELECT 1 \n FROM trail_share \n WHERE trail_share.trail = trails.id \n AND trail_share.actor = activitypub_actors.id\n ) GROUP BY activitypub_actors.id;"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("_clone_U0cX")
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "_clone_rnMQ",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("4wbv9tz5zjdrjh1")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT activitypub_actors.id, activitypub_actors.user, COALESCE(printf(\"%.2f\", MAX(trails.distance)), 0) AS max_distance,\n COALESCE(printf(\"%.2f\", MAX(trails.elevation_gain)), 0) AS max_elevation_gain, \n COALESCE(printf(\"%.2f\", MAX(trails.elevation_loss)), 0) AS max_elevation_loss, \n COALESCE(printf(\"%.2f\", MAX(trails.duration)), 0) AS max_duration, \n COALESCE(printf(\"%.2f\", MIN(trails.distance)), 0) AS min_distance, \n COALESCE(printf(\"%.2f\", MIN(trails.elevation_gain)), 0) AS min_elevation_gain, \n COALESCE(printf(\"%.2f\", MIN(trails.elevation_loss)), 0) AS min_elevation_loss, \n COALESCE(printf(\"%.2f\", MIN(trails.duration)), 0) AS min_duration \nFROM activitypub_actors \n LEFT JOIN trails ON \n activitypub_actors.id = trails.author OR \n trails.public = 1 OR \n EXISTS (\n SELECT 1 \n FROM trail_share \n WHERE trail_share.trail = trails.id \n AND trail_share.user = activitypub_actors.user\n ) GROUP BY activitypub_actors.id;"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "_clone_U0cX",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("_clone_rnMQ")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
80
db/migrations/1749554826_updated_trails_bounding_box.go
Normal file
80
db/migrations/1749554826_updated_trails_bounding_box.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("urytyc428mwlbqq")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT \n activitypub_actors.id, activitypub_actors.user, \n COALESCE(MAX(trails.lat), 0) AS max_lat, \n COALESCE(MAX(trails.lon), 0) AS max_lon, \n COALESCE(MIN(trails.lat), 0) AS min_lat, \n COALESCE(MIN(trails.lon), 0) AS min_lon \nFROM activitypub_actors \nLEFT JOIN trails \n ON activitypub_actors.id = trails.author \n OR trails.public = TRUE \n OR EXISTS (\n SELECT 1 \n FROM trail_share \n WHERE trail_share.trail = trails.id \n AND trail_share.actor = activitypub_actors.id\n ) \nGROUP BY activitypub_actors.id;"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("_clone_2GUq")
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "_clone_4wMO",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("urytyc428mwlbqq")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewQuery": "SELECT \n activitypub_actors.id, activitypub_actors.user, \n COALESCE(MAX(trails.lat), 0) AS max_lat, \n COALESCE(MAX(trails.lon), 0) AS max_lon, \n COALESCE(MIN(trails.lat), 0) AS min_lat, \n COALESCE(MIN(trails.lon), 0) AS min_lon \nFROM activitypub_actors \nLEFT JOIN trails \n ON activitypub_actors.id = trails.author \n OR trails.public = TRUE \n OR EXISTS (\n SELECT 1 \n FROM trail_share \n WHERE trail_share.trail = trails.id \n AND trail_share.user = activitypub_actors.id\n ) \nGROUP BY activitypub_actors.id;"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "_clone_2GUq",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("_clone_4wMO")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1749554910_updated_waypoints.go
Normal file
42
db/migrations/1749554910_updated_waypoints.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("goeo2ubp103rzp9")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "author = @request.auth.id || trails_via_waypoints.author.user ?= @request.auth.id || trails_via_waypoints.public ?= true || \n(@collection.trail_share.trail.id ?= trails_via_waypoints.id && @collection.trail_share.actor.user ?= @request.auth.id)",
|
||||||
|
"viewRule": "author = @request.auth.id || trails_via_waypoints.author.user ?= @request.auth.id || trails_via_waypoints.public ?= true || \n(@collection.trail_share.trail.id ?= trails_via_waypoints.id && @collection.trail_share.actor.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("goeo2ubp103rzp9")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "author = @request.auth.id || trails_via_waypoints.author.user ?= @request.auth.id || trails_via_waypoints.public ?= true || \n(@collection.trail_share.trail.id ?= trails_via_waypoints.id && @collection.trail_share.user ?= @request.auth.id)",
|
||||||
|
"viewRule": "author = @request.auth.id || trails_via_waypoints.author.user ?= @request.auth.id || trails_via_waypoints.public ?= true || \n(@collection.trail_share.trail.id ?= trails_via_waypoints.id && @collection.trail_share.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1749554952_updated_trails.go
Normal file
44
db/migrations/1749554952_updated_trails.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "author.user = @request.auth.id || public = true || (@request.auth.id != \"\" && trail_share_via_trail.actor.user ?= @request.auth.id)",
|
||||||
|
"updateRule": "author.user = @request.auth.id || (@request.auth.id != \"\" && trail_share_via_trail.trail = id && trail_share_via_trail.actor.user ?= @request.auth.id && trail_share_via_trail.permission = \"edit\") || (@request.auth.id != \"\" && author.isLocal = false)",
|
||||||
|
"viewRule": "author.user = @request.auth.id || public = true || (@request.auth.id != \"\" && trail_share_via_trail.actor.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "author.user = @request.auth.id || public = true || (@request.auth.id != \"\" && trail_share_via_trail.user ?= @request.auth.id)",
|
||||||
|
"updateRule": "author.user = @request.auth.id || (@request.auth.id != \"\" && trail_share_via_trail.trail = id && trail_share_via_trail.user ?= @request.auth.id && trail_share_via_trail.permission = \"edit\") || (@request.auth.id != \"\" && author.isLocal = false)",
|
||||||
|
"viewRule": "author.user = @request.auth.id || public = true || (@request.auth.id != \"\" && trail_share_via_trail.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1749555128_updated_summit_logs.go
Normal file
42
db/migrations/1749555128_updated_summit_logs.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || (@collection.trail_share.trail ?= trail && @collection.trail_share.actor.user ?= @request.auth.id)",
|
||||||
|
"viewRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || (@collection.trail_share.trail ?= trail && @collection.trail_share.actor.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || (@collection.trail_share.trail ?= trail && @collection.trail_share.trail ?= @request.auth.id)",
|
||||||
|
"viewRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || (@collection.trail_share.trail ?= trail && @collection.trail_share.trail ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1749555173_updated_comments.go
Normal file
44
db/migrations/1749555173_updated_comments.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lf06qip3f4d11yk")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (trail.author.user = @request.auth.id || trail.public = true || trail.trail_share_via_trail.actor.user ?= @request.auth.id)",
|
||||||
|
"listRule": "((@request.auth.id != \"\" && trail.author.user = @request.auth.id) || trail.public = true) || author = @request.auth.id || trail.trail_share_via_trail.actor.user ?= @request.auth.id",
|
||||||
|
"viewRule": "((@request.auth.id != \"\" && trail.author.user = @request.auth.id) || trail.public = true) || author = @request.auth.id || trail.trail_share_via_trail.actor.user ?= @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lf06qip3f4d11yk")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (trail.author.user = @request.auth.id || trail.public = true || trail.trail_share_via_trail.user ?= @request.auth.id)",
|
||||||
|
"listRule": "((@request.auth.id != \"\" && trail.author.user = @request.auth.id) || trail.public = true) || author = @request.auth.id || trail.trail_share_via_trail.user ?= @request.auth.id",
|
||||||
|
"viewRule": "((@request.auth.id != \"\" && trail.author.user = @request.auth.id) || trail.public = true) || author = @request.auth.id || trail.trail_share_via_trail.user ?= @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
62
db/migrations/1749555613_updated_trail_share.go
Normal file
62
db/migrations/1749555613_updated_trail_share.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("1mns8mlal6uf9ku")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "trail.author.user = @request.auth.id || actor.user = @request.auth.id",
|
||||||
|
"viewRule": "trail.author.user = @request.auth.id || actor.user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("yyzimwee")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("1mns8mlal6uf9ku")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "trail.author.user = @request.auth.id || user = @request.auth.id",
|
||||||
|
"viewRule": "trail.author.user = @request.auth.id || user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(3, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "yyzimwee",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
55
db/migrations/1749555614_migrate_ms_token.go
Normal file
55
db/migrations/1749555614_migrate_ms_token.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"pocketbase/util"
|
||||||
|
|
||||||
|
"github.com/meilisearch/meilisearch-go"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
client := meilisearch.New(os.Getenv("MEILI_URL"), meilisearch.WithAPIKey(os.Getenv("MEILI_MASTER_KEY")))
|
||||||
|
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
|
||||||
|
users, err := app.FindAllRecords("users")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, u := range users {
|
||||||
|
userId := u.Id
|
||||||
|
|
||||||
|
actor, err := app.FindFirstRecordByData("activitypub_actors", "user", userId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
searchRules := map[string]interface{}{
|
||||||
|
"lists": map[string]string{
|
||||||
|
"filter": "public = true OR author = " + actor.Id + " OR shares = " + actor.Id,
|
||||||
|
},
|
||||||
|
"trails": map[string]string{
|
||||||
|
"filter": "public = true OR author = " + actor.Id + " OR shares = " + actor.Id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := util.GenerateMeilisearchToken(searchRules, client)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u.Set("token", token)
|
||||||
|
if err := app.Save(u); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
// add down queries...
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
62
db/migrations/1749566277_updated_list_share.go
Normal file
62
db/migrations/1749566277_updated_list_share.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("1kot7t9na3hi0gl")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "list.author = @request.auth.id || actor.user = @request.auth.id",
|
||||||
|
"viewRule": "list.author = @request.auth.id || actor.user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(3, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation1148540665",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "actor",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("1kot7t9na3hi0gl")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "list.author = @request.auth.id || user = @request.auth.id",
|
||||||
|
"viewRule": "list.author = @request.auth.id || user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("relation1148540665")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
31
db/migrations/1749566278_migrate_list_share.go
Normal file
31
db/migrations/1749566278_migrate_list_share.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
shares, err := app.FindAllRecords("list_share")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range shares {
|
||||||
|
actor, err := app.FindFirstRecordByData("activitypub_actors", "user", s.GetString("user"))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.Set("actor", actor.Id)
|
||||||
|
err = app.Save(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(app core.App) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1749566445_updated_lists.go
Normal file
44
db/migrations/1749566445_updated_lists.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "author.user = @request.auth.id || public = true || (@request.auth.id != \"\" && list_share_via_list.actor.user ?= @request.auth.id)",
|
||||||
|
"updateRule": "author.user = @request.auth.id || (@request.auth.id != \"\" && list_share_via_list.list = id && list_share_via_list.actor.user ?= @request.auth.id && list_share_via_list.permission = \"edit\") || (@request.auth.id != \"\" && author.isLocal = false)",
|
||||||
|
"viewRule": "author.user = @request.auth.id || public = true || (@request.auth.id != \"\" && list_share_via_list.actor.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "author.user = @request.auth.id || public = true || (@request.auth.id != \"\" && list_share_via_list.user ?= @request.auth.id)",
|
||||||
|
"updateRule": "author.user = @request.auth.id || (@request.auth.id != \"\" && list_share_via_list.list = id && list_share_via_list.user ?= @request.auth.id && list_share_via_list.permission = \"edit\") || (@request.auth.id != \"\" && author.isLocal = false)",
|
||||||
|
"viewRule": "author.user = @request.auth.id || public = true || (@request.auth.id != \"\" && list_share_via_list.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1749566456_updated_list_share.go
Normal file
44
db/migrations/1749566456_updated_list_share.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("1kot7t9na3hi0gl")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("mix12kkh")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("1kot7t9na3hi0gl")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "mix12kkh",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "user",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
48
db/migrations/1749566852_updated_list_share.go
Normal file
48
db/migrations/1749566852_updated_list_share.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("1kot7t9na3hi0gl")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "list.author.user = @request.auth.id",
|
||||||
|
"deleteRule": "list.author.user = @request.auth.id",
|
||||||
|
"listRule": "list.author.user = @request.auth.id || actor.user = @request.auth.id",
|
||||||
|
"updateRule": "list.author.user = @request.auth.id",
|
||||||
|
"viewRule": "list.author.user = @request.auth.id || actor.user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("1kot7t9na3hi0gl")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "list.author = @request.auth.id",
|
||||||
|
"deleteRule": "list.author = @request.auth.id",
|
||||||
|
"listRule": "list.author = @request.auth.id || actor.user = @request.auth.id",
|
||||||
|
"updateRule": "list.author = @request.auth.id",
|
||||||
|
"viewRule": "list.author = @request.auth.id || actor.user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
40
db/migrations/1749650389_updated_summit_logs.go
Normal file
40
db/migrations/1749650389_updated_summit_logs.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (trail.author.user = @request.auth.id || trail.public = true || trail.trail_share_via_trail.actor.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "@request.auth.id != \"\" && (trail.author.user = @request.auth.id || trail.public = true)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1749650422_updated_summit_logs.go
Normal file
42
db/migrations/1749650422_updated_summit_logs.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || trail.trail_share_via_trail.actor.user ?= @request.auth.id",
|
||||||
|
"viewRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || trail.trail_share_via_trail.actor.user ?= @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || (@collection.trail_share.trail ?= trail && @collection.trail_share.actor.user ?= @request.auth.id)",
|
||||||
|
"viewRule": "(@request.auth.id != \"\" && (author.user = @request.auth.id || trail.author.user = @request.auth.id)) || trail.public = true || (@collection.trail_share.trail ?= trail && @collection.trail_share.actor.user ?= @request.auth.id)"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
103
db/migrations/1749717023_created_trail_like.go
Normal file
103
db/migrations/1749717023_created_trail_like.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
jsonData := `{
|
||||||
|
"createRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"autogeneratePattern": "[a-z0-9]{15}",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "text3208210256",
|
||||||
|
"max": 15,
|
||||||
|
"min": 15,
|
||||||
|
"name": "id",
|
||||||
|
"pattern": "^[a-z0-9]+$",
|
||||||
|
"presentable": false,
|
||||||
|
"primaryKey": true,
|
||||||
|
"required": true,
|
||||||
|
"system": true,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "e864strfxo14pm4",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation2993194383",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "trail",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cascadeDelete": true,
|
||||||
|
"collectionId": "pbc_1295301207",
|
||||||
|
"hidden": false,
|
||||||
|
"id": "relation1148540665",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"minSelect": 0,
|
||||||
|
"name": "actor",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "relation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "autodate2990389176",
|
||||||
|
"name": "created",
|
||||||
|
"onCreate": true,
|
||||||
|
"onUpdate": false,
|
||||||
|
"presentable": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "autodate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "autodate3332085495",
|
||||||
|
"name": "updated",
|
||||||
|
"onCreate": true,
|
||||||
|
"onUpdate": true,
|
||||||
|
"presentable": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "autodate"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"id": "pbc_1995454416",
|
||||||
|
"indexes": [
|
||||||
|
"CREATE UNIQUE INDEX ` + "`" + `idx_ywIkmeaSFo` + "`" + ` ON ` + "`" + `trail_like` + "`" + ` (\n ` + "`" + `trail` + "`" + `,\n ` + "`" + `actor` + "`" + `\n)"
|
||||||
|
],
|
||||||
|
"listRule": null,
|
||||||
|
"name": "trail_like",
|
||||||
|
"system": false,
|
||||||
|
"type": "base",
|
||||||
|
"updateRule": null,
|
||||||
|
"viewRule": null
|
||||||
|
}`
|
||||||
|
|
||||||
|
collection := &core.Collection{}
|
||||||
|
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_1995454416")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Delete(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
46
db/migrations/1749717428_updated_trail_like.go
Normal file
46
db/migrations/1749717428_updated_trail_like.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_1995454416")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": "trail.author.user = @request.auth.id || trail.public = true || trail.trail_share_via_trail.actor.user ?= @request.auth.id || actor.user = @request.auth.id",
|
||||||
|
"deleteRule": "actor.user = @request.auth.id",
|
||||||
|
"listRule": "trail.author.user = @request.auth.id || trail.public = true || trail.trail_share_via_trail.actor.user ?= @request.auth.id || actor.user = @request.auth.id",
|
||||||
|
"viewRule": "trail.author.user = @request.auth.id || trail.public = true || trail.trail_share_via_trail.actor.user ?= @request.auth.id || actor.user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_1995454416")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"createRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"listRule": null,
|
||||||
|
"viewRule": null
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1749831369_update_sortable_attributes.go
Normal file
42
db/migrations/1749831369_update_sortable_attributes.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/meilisearch/meilisearch-go"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
client := meilisearch.New(os.Getenv("MEILI_URL"), meilisearch.WithAPIKey(os.Getenv("MEILI_MASTER_KEY")))
|
||||||
|
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
|
||||||
|
_, err := client.Index("trails").UpdateSortableAttributes(&[]string{
|
||||||
|
"created", "date", "difficulty", "distance", "elevation_gain", "elevation_loss", "name", "duration", "author", "like_count",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.Index("trails").UpdateFilterableAttributes(&[]string{
|
||||||
|
"_geo", "author", "category", "completed", "date", "difficulty", "distance", "elevation_gain", "elevation_loss", "public", "shares", "tags", "likes",
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}, func(app core.App) error {
|
||||||
|
_, err := client.Index("trails").UpdateSortableAttributes(&[]string{
|
||||||
|
"created", "date", "difficulty", "distance", "elevation_gain", "elevation_loss", "name", "duration", "author",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.Index("trails").UpdateFilterableAttributes(&[]string{
|
||||||
|
"_geo", "author", "category", "completed", "date", "difficulty", "distance", "elevation_gain", "elevation_loss", "public", "shares", "tags",
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
67
db/migrations/1749836174_updated_notifications.go
Normal file
67
db/migrations/1749836174_updated_notifications.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "b57prsbu",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"name": "type",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "select",
|
||||||
|
"values": [
|
||||||
|
"new_follower",
|
||||||
|
"trail_comment",
|
||||||
|
"trail_share",
|
||||||
|
"list_share",
|
||||||
|
"summit_log_create",
|
||||||
|
"trail_like"
|
||||||
|
]
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "b57prsbu",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"name": "type",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "select",
|
||||||
|
"values": [
|
||||||
|
"new_follower",
|
||||||
|
"trail_comment",
|
||||||
|
"trail_share",
|
||||||
|
"list_share",
|
||||||
|
"summit_log_create"
|
||||||
|
]
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
43
db/migrations/1749837201_updated_trails.go
Normal file
43
db/migrations/1749837201_updated_trails.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(23, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "number851275141",
|
||||||
|
"max": null,
|
||||||
|
"min": 0,
|
||||||
|
"name": "like_count",
|
||||||
|
"onlyInt": true,
|
||||||
|
"presentable": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"type": "number"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove field
|
||||||
|
collection.Fields.RemoveById("number851275141")
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
40
db/migrations/1749837751_updated_trail_like.go
Normal file
40
db/migrations/1749837751_updated_trail_like.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_1995454416")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewRule": "actor.user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_1995454416")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"viewRule": "trail.author.user = @request.auth.id || trail.public = true || trail.trail_share_via_trail.actor.user ?= @request.auth.id || actor.user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
82
db/migrations/1749894936_updated_trails.go
Normal file
82
db/migrations/1749894936_updated_trails.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(11, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "aqbpyawe",
|
||||||
|
"maxSelect": 99,
|
||||||
|
"maxSize": 20971520,
|
||||||
|
"mimeTypes": [
|
||||||
|
"image/jpeg",
|
||||||
|
"image/vnd.mozilla.apng",
|
||||||
|
"image/png",
|
||||||
|
"image/webp",
|
||||||
|
"image/svg+xml",
|
||||||
|
"image/heic",
|
||||||
|
"video/mp4",
|
||||||
|
"video/webm",
|
||||||
|
"video/ogg"
|
||||||
|
],
|
||||||
|
"name": "photos",
|
||||||
|
"presentable": false,
|
||||||
|
"protected": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"thumbs": [
|
||||||
|
"600x0"
|
||||||
|
],
|
||||||
|
"type": "file"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(11, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "aqbpyawe",
|
||||||
|
"maxSelect": 99,
|
||||||
|
"maxSize": 20971520,
|
||||||
|
"mimeTypes": [
|
||||||
|
"image/jpeg",
|
||||||
|
"image/vnd.mozilla.apng",
|
||||||
|
"image/png",
|
||||||
|
"image/webp",
|
||||||
|
"image/svg+xml",
|
||||||
|
"image/heic",
|
||||||
|
"video/mp4",
|
||||||
|
"video/webm",
|
||||||
|
"video/ogg"
|
||||||
|
],
|
||||||
|
"name": "photos",
|
||||||
|
"presentable": false,
|
||||||
|
"protected": false,
|
||||||
|
"required": false,
|
||||||
|
"system": false,
|
||||||
|
"thumbs": [],
|
||||||
|
"type": "file"
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1749902683_updated_activitypub_actors.go
Normal file
42
db/migrations/1749902683_updated_activitypub_actors.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_1295301207")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "user.settings_via_user.privacy.account != 'private' || user = @request.auth.id",
|
||||||
|
"viewRule": "user.settings_via_user.privacy.account != 'private' || user = @request.auth.id"
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("pbc_1295301207")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"listRule": "",
|
||||||
|
"viewRule": ""
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1750259236_updated_comments.go
Normal file
42
db/migrations/1750259236_updated_comments.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lf06qip3f4d11yk")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": [
|
||||||
|
"CREATE UNIQUE INDEX ` + "`" + `idx_4T3m08OsP1` + "`" + ` ON ` + "`" + `comments` + "`" + ` (` + "`" + `iri` + "`" + `) WHERE iri IS NOT NULL AND iri != \"\";"
|
||||||
|
]
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lf06qip3f4d11yk")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": []
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1750259275_updated_lists.go
Normal file
44
db/migrations/1750259275_updated_lists.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": [
|
||||||
|
"CREATE UNIQUE INDEX ` + "`" + `idx_hLtEU5XGWL` + "`" + ` ON ` + "`" + `lists` + "`" + ` (` + "`" + `iri` + "`" + `) WHERE iri IS NOT NULL AND iri != \"\";"
|
||||||
|
]
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("r6gu2ajyidy1x69")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": [
|
||||||
|
"CREATE INDEX ` + "`" + `idx_hLtEU5XGWL` + "`" + ` ON ` + "`" + `lists` + "`" + ` (` + "`" + `iri` + "`" + `)"
|
||||||
|
]
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
42
db/migrations/1750259298_updated_summit_logs.go
Normal file
42
db/migrations/1750259298_updated_summit_logs.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": [
|
||||||
|
"CREATE UNIQUE INDEX ` + "`" + `idx_iSbmEqYXbV` + "`" + ` ON ` + "`" + `summit_logs` + "`" + ` (` + "`" + `iri` + "`" + `) WHERE iri IS NOT NULL AND iri != \"\";"
|
||||||
|
]
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": []
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
44
db/migrations/1750259324_updated_trails.go
Normal file
44
db/migrations/1750259324_updated_trails.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": [
|
||||||
|
"CREATE UNIQUE INDEX ` + "`" + `idx_6tD5RqfVk2` + "`" + ` ON ` + "`" + `trails` + "`" + ` (` + "`" + `iri` + "`" + `) WHERE iri IS NOT NULL AND iri != \"\";"
|
||||||
|
]
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("e864strfxo14pm4")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update collection data
|
||||||
|
if err := json.Unmarshal([]byte(`{
|
||||||
|
"indexes": [
|
||||||
|
"CREATE INDEX ` + "`" + `idx_6tD5RqfVk2` + "`" + ` ON ` + "`" + `trails` + "`" + ` (` + "`" + `iri` + "`" + `)"
|
||||||
|
]
|
||||||
|
}`), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
70
db/migrations/1750264310_updated_notifications.go
Normal file
70
db/migrations/1750264310_updated_notifications.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "b57prsbu",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"name": "type",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "select",
|
||||||
|
"values": [
|
||||||
|
"new_follower",
|
||||||
|
"trail_comment",
|
||||||
|
"trail_share",
|
||||||
|
"list_share",
|
||||||
|
"summit_log_create",
|
||||||
|
"trail_like",
|
||||||
|
"comment_mention",
|
||||||
|
"trail_mention"
|
||||||
|
]
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "b57prsbu",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"name": "type",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "select",
|
||||||
|
"values": [
|
||||||
|
"new_follower",
|
||||||
|
"trail_comment",
|
||||||
|
"trail_share",
|
||||||
|
"list_share",
|
||||||
|
"summit_log_create",
|
||||||
|
"trail_like"
|
||||||
|
]
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
73
db/migrations/1750267445_updated_notifications.go
Normal file
73
db/migrations/1750267445_updated_notifications.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "b57prsbu",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"name": "type",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "select",
|
||||||
|
"values": [
|
||||||
|
"new_follower",
|
||||||
|
"trail_comment",
|
||||||
|
"trail_share",
|
||||||
|
"list_share",
|
||||||
|
"summit_log_create",
|
||||||
|
"trail_like",
|
||||||
|
"comment_mention",
|
||||||
|
"trail_mention",
|
||||||
|
"summit_log_mention"
|
||||||
|
]
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
}, func(app core.App) error {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("khrcci2uqknny8h")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update field
|
||||||
|
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
|
||||||
|
"hidden": false,
|
||||||
|
"id": "b57prsbu",
|
||||||
|
"maxSelect": 1,
|
||||||
|
"name": "type",
|
||||||
|
"presentable": false,
|
||||||
|
"required": true,
|
||||||
|
"system": false,
|
||||||
|
"type": "select",
|
||||||
|
"values": [
|
||||||
|
"new_follower",
|
||||||
|
"trail_comment",
|
||||||
|
"trail_share",
|
||||||
|
"list_share",
|
||||||
|
"summit_log_create",
|
||||||
|
"trail_like",
|
||||||
|
"comment_mention",
|
||||||
|
"trail_mention"
|
||||||
|
]
|
||||||
|
}`)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.Save(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
595
db/util/activitypub.go
Normal file
595
db/util/activitypub.go
Normal file
@@ -0,0 +1,595 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
pub "github.com/go-ap/activitypub"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/filesystem"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ActorFromUser(app core.App, u *core.Record) (*core.Record, error) {
|
||||||
|
encryptionKey := os.Getenv("POCKETBASE_ENCRYPTION_KEY")
|
||||||
|
if len(encryptionKey) == 0 {
|
||||||
|
return nil, fmt.Errorf("POCKETBASE_ENCRYPTION_KEY not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
collection, err := app.FindCollectionByNameOrId("activitypub_actors")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
priv, pub, err := generateKeyPair()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
privBytes := x509.MarshalPKCS1PrivateKey(priv)
|
||||||
|
|
||||||
|
privEncrypted, err := security.Encrypt(privBytes, encryptionKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pubBytes, err := x509.MarshalPKIXPublicKey(pub)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pubPem := pem.EncodeToMemory(&pem.Block{
|
||||||
|
Type: "PUBLIC KEY",
|
||||||
|
Bytes: pubBytes,
|
||||||
|
})
|
||||||
|
|
||||||
|
settings, err := app.FindFirstRecordByData("settings", "user", u.Id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return nil, fmt.Errorf("ORIGIN environment variable not set")
|
||||||
|
}
|
||||||
|
id := fmt.Sprintf("%s/api/v1/activitypub/user/%s", origin, strings.ToLower(u.GetString("username")))
|
||||||
|
|
||||||
|
url, err := url.Parse(origin)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
domain := strings.TrimPrefix(url.Hostname(), "www.")
|
||||||
|
|
||||||
|
record.Set("username", strings.ToLower(u.GetString("username")))
|
||||||
|
record.Set("preferred_username", u.GetString("username"))
|
||||||
|
record.Set("domain", domain)
|
||||||
|
record.Set("summary", settings.GetString("bio"))
|
||||||
|
record.Set("published", u.GetDateTime("created"))
|
||||||
|
record.Set("iri", id)
|
||||||
|
if u.GetString("avatar") != "" {
|
||||||
|
record.Set("icon", fmt.Sprintf("%s/api/v1/files/users/%s/%s", origin, u.Id, u.GetString("avatar")))
|
||||||
|
}
|
||||||
|
record.Set("inbox", id+"/inbox")
|
||||||
|
record.Set("outbox", id+"/outbox")
|
||||||
|
record.Set("followers", id+"/followers")
|
||||||
|
record.Set("following", id+"/following")
|
||||||
|
record.Set("isLocal", true)
|
||||||
|
record.Set("public_key", string(pubPem))
|
||||||
|
record.Set("private_key", privEncrypted)
|
||||||
|
record.Set("user", u.Id)
|
||||||
|
record.Set("last_fetched", time.Now())
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return record, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateKeyPair() (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
||||||
|
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pub := &priv.PublicKey
|
||||||
|
return priv, pub, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SyncOutbox(app core.App, actor *core.Record) error {
|
||||||
|
return fetchOutboxPage(app, actor, actor.GetString("outbox")+"?page=1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchOutboxPage(app core.App, actor *core.Record, pageURL string) error {
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodGet, pageURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Add("Accept", `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`)
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var page pub.OrderedCollectionPage
|
||||||
|
err = json.Unmarshal(body, &page)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range page.OrderedItems {
|
||||||
|
activity, err := pub.ToActivity(item)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if activity.Type != pub.CreateType {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if page.Next != nil {
|
||||||
|
return fetchOutboxPage(app, actor, page.Next.GetID().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TrailFromActivity(activity pub.Activity, app core.App, actor *core.Record) (*core.Record, error) {
|
||||||
|
t, err := pub.ToObject(activity.Object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
record, err := app.FindFirstRecordByData("trails", "iri", t.ID.String())
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("trails")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
record = core.NewRecord(collection)
|
||||||
|
record.Set("id", security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var distance, duration, elevation_gain, elevation_loss float64
|
||||||
|
var diffculty, category string
|
||||||
|
trailTags := []string{}
|
||||||
|
tags, err := pub.ToItemCollection(t.Tag)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tag := range tags.Collection() {
|
||||||
|
tagObj, err := pub.ToObject(tag)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
content := tagObj.Content.First().Value.String()
|
||||||
|
switch tagObj.Name.First().Value.String() {
|
||||||
|
case "category":
|
||||||
|
category = content
|
||||||
|
case "difficulty":
|
||||||
|
diffculty = content
|
||||||
|
case "elevation_gain":
|
||||||
|
elevation_gain, err = strconv.ParseFloat(content[:len(content)-1], 64)
|
||||||
|
case "elevation_loss":
|
||||||
|
elevation_loss, err = strconv.ParseFloat(content[:len(content)-1], 64)
|
||||||
|
case "duration":
|
||||||
|
duration, err = strconv.ParseFloat(content[:len(content)-1], 64)
|
||||||
|
case "distance":
|
||||||
|
distance, err = strconv.ParseFloat(content[:len(content)-1], 64)
|
||||||
|
case "tag":
|
||||||
|
existingTag, err := app.FindFirstRecordByData("tags", "name", content)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("tags")
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
existingTag = core.NewRecord(collection)
|
||||||
|
existingTag.Set("name", content)
|
||||||
|
err = app.Save(existingTag)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trailTags = append(trailTags, existingTag.Id)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record.Set("name", t.Name.First().Value)
|
||||||
|
record.Set("description", t.Content.First().Value)
|
||||||
|
record.Set("location", t.Location.(*pub.Place).Name.First().Value)
|
||||||
|
record.Set("lat", t.Location.(*pub.Place).Latitude)
|
||||||
|
record.Set("lon", t.Location.(*pub.Place).Longitude)
|
||||||
|
record.Set("distance", distance)
|
||||||
|
record.Set("elevation_gain", elevation_gain)
|
||||||
|
record.Set("elevation_loss", elevation_loss)
|
||||||
|
record.Set("duration", duration)
|
||||||
|
record.Set("difficulty", diffculty)
|
||||||
|
record.Set("date", t.StartTime.Unix())
|
||||||
|
record.Set("tags", trailTags)
|
||||||
|
record.Set("public", true)
|
||||||
|
record.Set("iri", t.ID.String())
|
||||||
|
record.Set("author", actor.Id)
|
||||||
|
|
||||||
|
categoryRecord, err := app.FindFirstRecordByData("categories", "name", category)
|
||||||
|
if err == nil {
|
||||||
|
record.Set("category", categoryRecord.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Attachment != nil {
|
||||||
|
|
||||||
|
attachments, err := pub.ToItemCollection(t.Attachment)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
photoURLs := []string{}
|
||||||
|
gpxURL := ""
|
||||||
|
for _, a := range attachments.Collection() {
|
||||||
|
attachment, err := pub.ToObject(a)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if attachment.Type == pub.DocumentType && attachment.MediaType == "application/xml+gpx" {
|
||||||
|
gpxURL = attachment.URL.GetLink().String()
|
||||||
|
} else if attachment.Type == pub.ImageType {
|
||||||
|
photoURLs = append(photoURLs, attachment.URL.GetLink().String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(photoURLs) > 0 {
|
||||||
|
photos := make([]*filesystem.File, len(photoURLs))
|
||||||
|
for i, purl := range photoURLs {
|
||||||
|
photo, err := filesystem.NewFileFromURL(context.Background(), purl)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
photos[i] = photo
|
||||||
|
}
|
||||||
|
|
||||||
|
record.Set("photos", photos)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gpxURL != "" {
|
||||||
|
gpx, err := filesystem.NewFileFromURL(context.Background(), gpxURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
record.Set("gpx", gpx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return record, app.Save(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ObjectFromTrail(app core.App, trail *core.Record, mentions *pub.ItemCollection) (*pub.Object, error) {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return nil, fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
trailAuthor, err := app.FindRecordById("activitypub_actors", trail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
errs := app.ExpandRecord(trail, []string{"tags"}, nil)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return nil, fmt.Errorf("failed to expand tags: %v", errs)
|
||||||
|
}
|
||||||
|
errs = app.ExpandRecord(trail, []string{"category"}, nil)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return nil, fmt.Errorf("failed to expand category: %v", errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
category := ""
|
||||||
|
categoryRecord := trail.ExpandedOne("category")
|
||||||
|
if categoryRecord != nil {
|
||||||
|
category = categoryRecord.GetString("name")
|
||||||
|
}
|
||||||
|
|
||||||
|
tagRecords := trail.ExpandedAll("tags")
|
||||||
|
|
||||||
|
tags := pub.ItemCollection{
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "category")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, category)),
|
||||||
|
},
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "difficulty")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, trail.GetString("difficulty"))),
|
||||||
|
},
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "elevation_gain")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, fmt.Sprintf("%fm", trail.GetFloat("elevation_gain")))),
|
||||||
|
},
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "elevation_loss")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, fmt.Sprintf("%fm", trail.GetFloat("elevation_loss")))),
|
||||||
|
},
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "distance")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, fmt.Sprintf("%fm", trail.GetFloat("distance")))),
|
||||||
|
},
|
||||||
|
pub.Object{
|
||||||
|
Type: pub.NoteType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "duration")),
|
||||||
|
Content: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, fmt.Sprintf("%fm", trail.GetFloat("duration")))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if mentions != nil {
|
||||||
|
for _, m := range *mentions {
|
||||||
|
tags.Append(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range tagRecords {
|
||||||
|
hashtag := pub.ObjectNew(pub.NoteType)
|
||||||
|
hashtag.Name = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, "tag"))
|
||||||
|
hashtag.Content = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, v.GetString("name")))
|
||||||
|
|
||||||
|
tags.Append(hashtag)
|
||||||
|
}
|
||||||
|
|
||||||
|
photos := trail.GetStringSlice("photos")
|
||||||
|
|
||||||
|
gpx := ""
|
||||||
|
if trail.GetString("gpx") != "" {
|
||||||
|
gpx = fmt.Sprintf("%s/api/v1/files/trails/%s/%s", origin, trail.Id, trail.GetString("gpx"))
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments := make(pub.ItemCollection, max(len(photos), 2))
|
||||||
|
for i := range min(len(photos), 3) {
|
||||||
|
iri := fmt.Sprintf("%s/api/v1/files/trails/%s/%s", origin, trail.Id, photos[i])
|
||||||
|
|
||||||
|
attachments[i] = pub.Image{
|
||||||
|
Type: pub.ImageType,
|
||||||
|
MediaType: "image/jpeg",
|
||||||
|
URL: pub.IRI(iri),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if gpx != "" {
|
||||||
|
attachments.Append(pub.Document{
|
||||||
|
Type: pub.DocumentType,
|
||||||
|
MediaType: "application/xml+gpx",
|
||||||
|
URL: pub.IRI(gpx),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
activityURL := fmt.Sprintf("%s/trail/view/@%s/%s", origin, trailAuthor.GetString("username"), trail.Id)
|
||||||
|
activityContent := fmt.Sprintf("<h1>%s</h1>%s<p><a href=\"%s\">%s</a></p>", trail.GetString("name"), trail.GetString("description"), activityURL, activityURL)
|
||||||
|
|
||||||
|
trailObject := pub.ObjectNew(pub.NoteType)
|
||||||
|
|
||||||
|
trailObject.Name = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, trail.GetString("name")))
|
||||||
|
trailObject.Content = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, activityContent))
|
||||||
|
trailObject.Location = pub.Place{
|
||||||
|
Type: pub.PlaceType,
|
||||||
|
Name: pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, trail.GetString("location"))),
|
||||||
|
Latitude: trail.GetFloat("lat"),
|
||||||
|
Longitude: trail.GetFloat("lon"),
|
||||||
|
}
|
||||||
|
trailObject.AttributedTo = pub.IRI(trailAuthor.GetString("iri"))
|
||||||
|
trailObject.Published = trail.GetDateTime("created").Time()
|
||||||
|
trailObject.ID = pub.IRI(fmt.Sprintf("%s/api/v1/trail/%s", origin, trail.Id))
|
||||||
|
trailObject.URL = pub.IRI(activityURL)
|
||||||
|
|
||||||
|
trailObject.StartTime = trail.GetDateTime("date").Time()
|
||||||
|
trailObject.Attachment = attachments
|
||||||
|
|
||||||
|
trailObject.Tag = tags
|
||||||
|
return trailObject, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListFromActivity(activity pub.Activity, app core.App, actor *core.Record) (*core.Record, error) {
|
||||||
|
l, err := pub.ToObject(activity.Object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
record, err := app.FindFirstRecordByData("lists", "iri", l.ID.String())
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
collection, err := app.FindCollectionByNameOrId("lists")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
record = core.NewRecord(collection)
|
||||||
|
record.Set("id", security.RandomStringWithAlphabet(core.DefaultIdLength, core.DefaultIdAlphabet))
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record.Set("name", l.Name.First().Value)
|
||||||
|
record.Set("description", l.Content.First().Value)
|
||||||
|
record.Set("public", true)
|
||||||
|
record.Set("iri", l.ID.String())
|
||||||
|
record.Set("author", actor.Id)
|
||||||
|
|
||||||
|
if l.Attachment != nil {
|
||||||
|
|
||||||
|
avatarURL := ""
|
||||||
|
attachments, err := pub.ToItemCollection(l.Attachment)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range attachments.Collection() {
|
||||||
|
attachment, err := pub.ToObject(a)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if attachment.Type == pub.ImageType {
|
||||||
|
avatarURL = attachment.URL.GetLink().String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if avatarURL != "" {
|
||||||
|
avatar, err := filesystem.NewFileFromURL(context.Background(), avatarURL)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
record.Set("avatar", avatar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = app.Save(record)
|
||||||
|
|
||||||
|
return record, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ObjectFromList(app core.App, list *core.Record) (*pub.Object, error) {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return nil, fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
listAuthor, err := app.FindRecordById("activitypub_actors", list.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
avatar := ""
|
||||||
|
if list.GetString("avatar") != "" {
|
||||||
|
avatar = fmt.Sprintf("%s/api/v1/files/lists/%s/%s", origin, list.Id, list.GetString("avatar"))
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments := make(pub.ItemCollection, 2)
|
||||||
|
if avatar != "" {
|
||||||
|
attachments[0] = pub.Image{
|
||||||
|
Type: pub.ImageType,
|
||||||
|
MediaType: "image/jpeg",
|
||||||
|
URL: pub.IRI(avatar),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activityURL := fmt.Sprintf("%s/lists/@%s/%s", origin, listAuthor.GetString("username"), list.Id)
|
||||||
|
activityContent := fmt.Sprintf("%s<p><a href=\"%s\">%s</a></p>", list.GetString("description"), activityURL, activityURL)
|
||||||
|
|
||||||
|
listObject := pub.ObjectNew(pub.NoteType)
|
||||||
|
listObject.Name = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, list.GetString("name")))
|
||||||
|
listObject.Content = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, activityContent))
|
||||||
|
|
||||||
|
listObject.AttributedTo = pub.IRI(listAuthor.GetString("iri"))
|
||||||
|
listObject.Published = list.GetDateTime("created").Time()
|
||||||
|
listObject.ID = pub.IRI(fmt.Sprintf("%s/api/v1/list/%s", origin, list.Id))
|
||||||
|
listObject.URL = pub.IRI(activityURL)
|
||||||
|
listObject.Attachment = attachments
|
||||||
|
return listObject, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ObjectFromComment(app core.App, comment *core.Record, mentions *pub.ItemCollection) (*pub.Object, error) {
|
||||||
|
origin := os.Getenv("ORIGIN")
|
||||||
|
if origin == "" {
|
||||||
|
return nil, fmt.Errorf("ORIGIN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
commentAuthor, err := app.FindRecordById("activitypub_actors", comment.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
commentTrail, err := app.FindRecordById("trails", comment.GetString("trail"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
commentTrailAuthor, err := app.FindRecordById("activitypub_actors", commentTrail.GetString("author"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
trailURL := ""
|
||||||
|
if commentTrailAuthor.GetBool("isLocal") {
|
||||||
|
trailURL = fmt.Sprintf("https://%s/api/v1/trail/%s", commentTrailAuthor.GetString("domain"), comment.GetString("trail"))
|
||||||
|
} else {
|
||||||
|
trailURL = commentTrail.GetString("iri")
|
||||||
|
}
|
||||||
|
|
||||||
|
commentObject := pub.ObjectNew(pub.NoteType)
|
||||||
|
commentObject.ID = pub.IRI(fmt.Sprintf("%s/api/v1/comment/%s", origin, comment.Id))
|
||||||
|
commentObject.Content = pub.NaturalLanguageValuesNew(pub.LangRefValueNew(pub.NilLangRef, comment.GetString("text")))
|
||||||
|
commentObject.Published = comment.GetDateTime("created").Time()
|
||||||
|
commentObject.AttributedTo = pub.IRI(commentAuthor.GetString("iri"))
|
||||||
|
commentObject.InReplyTo = pub.IRI(trailURL)
|
||||||
|
|
||||||
|
if mentions != nil {
|
||||||
|
commentObject.Tag = *mentions
|
||||||
|
}
|
||||||
|
|
||||||
|
return commentObject, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TrailObjectFromIRI(iri string) (*pub.Object, error) {
|
||||||
|
fetchURL := strings.Replace(iri, "api/v1/trail", "api/v1/activitypub/trail", 1)
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodGet, fetchURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var object pub.Object
|
||||||
|
err = json.Unmarshal(body, &object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &object, nil
|
||||||
|
}
|
||||||
@@ -17,12 +17,15 @@ type EmailData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var notificationTemplates = map[NotificationType]string{
|
var notificationTemplates = map[NotificationType]string{
|
||||||
TrailCreate: "{{.Author}} has created a new trail: {{.trail}}.",
|
TrailShare: "{{.Author}} has shared a trail with you: {{.trail}}.",
|
||||||
TrailShare: "{{.Author}} has shared a trail with you: {{.trail}}.",
|
ListShare: "{{.Author}} has shared a list with you: {{.list}}.",
|
||||||
ListCreate: "{{.Author}} has created a new list: {{.list}}.",
|
NewFollower: "Good news! You have a new follower: {{.Author}}.",
|
||||||
ListShare: "{{.Author}} has shared a list with you: {{.list}}.",
|
TrailComment: "{{.Author}} commented on your trail '{{.trail_name}}': '{{.comment}}'.",
|
||||||
NewFollower: "Good news! You have a new follower: {{.Author}}.",
|
SummitLogCreate: "{{.Author}} created a summit log on your trail '{{.trail_name}}'.",
|
||||||
TrailComment: "{{.Author}} commented on your trail '{{.trail}}': '{{.comment}}'.",
|
TrailLike: "{{.Author}} liked your trail '{{.trail_name}}'.",
|
||||||
|
CommentMention: "{{.Author}} mentioned you in a comment.",
|
||||||
|
TrailMention: "{{.Author}} mentioned you in a trail.",
|
||||||
|
SummitLogMention: "{{.Author}} mentioned you in a summit log.",
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateHTML(appUrl string, recipientName string, authorName string, notificationType NotificationType, metadata map[string]string) (string, error) {
|
func GenerateHTML(appUrl string, recipientName string, authorName string, notificationType NotificationType, metadata map[string]string) (string, error) {
|
||||||
|
|||||||
@@ -2,12 +2,17 @@ package util
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
|
||||||
"github.com/meilisearch/meilisearch-go"
|
"github.com/meilisearch/meilisearch-go"
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/twpayne/go-gpx"
|
"github.com/twpayne/go-gpx"
|
||||||
"github.com/twpayne/go-polyline"
|
"github.com/twpayne/go-polyline"
|
||||||
@@ -31,16 +36,32 @@ func documentFromTrailRecord(app core.App, r *core.Record, author *core.Record,
|
|||||||
tags[i] = v.GetString("name")
|
tags[i] = v.GetString("name")
|
||||||
}
|
}
|
||||||
|
|
||||||
polyline, err := getPolyline(app, r)
|
category := ""
|
||||||
|
trailCategory := r.ExpandedOne("category")
|
||||||
|
if trailCategory != nil {
|
||||||
|
category = trailCategory.GetString("name")
|
||||||
|
}
|
||||||
|
|
||||||
|
// polyline, err := getPolyline(app, r)
|
||||||
|
// if err != nil {
|
||||||
|
// polyline = ""
|
||||||
|
// }
|
||||||
|
|
||||||
|
domain := ""
|
||||||
|
if !author.GetBool("isLocal") {
|
||||||
|
domain = author.GetString("domain")
|
||||||
|
}
|
||||||
|
|
||||||
|
logCount, err := app.CountRecords("summit_logs", dbx.NewExp("trail={:id}", dbx.Params{"id": r.Id}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
document := map[string]interface{}{
|
document := map[string]any{
|
||||||
"id": r.Id,
|
"id": r.Id,
|
||||||
"author": r.GetString("author"),
|
"author": author.Id,
|
||||||
"author_name": author.GetString("username"),
|
"author_name": author.GetString("username"),
|
||||||
"author_avatar": author.GetString("avatar"),
|
"author_avatar": author.GetString("icon"),
|
||||||
"name": r.GetString("name"),
|
"name": r.GetString("name"),
|
||||||
"description": r.GetString("description"),
|
"description": r.GetString("description"),
|
||||||
"location": r.GetString("location"),
|
"location": r.GetString("location"),
|
||||||
@@ -49,15 +70,17 @@ func documentFromTrailRecord(app core.App, r *core.Record, author *core.Record,
|
|||||||
"elevation_loss": r.GetFloat("elevation_loss"),
|
"elevation_loss": r.GetFloat("elevation_loss"),
|
||||||
"duration": r.GetFloat("duration"),
|
"duration": r.GetFloat("duration"),
|
||||||
"difficulty": r.Get("difficulty"),
|
"difficulty": r.Get("difficulty"),
|
||||||
"category": r.Get("category"),
|
"category": category,
|
||||||
"completed": len(r.GetStringSlice("summit_logs")) > 0,
|
"completed": logCount > 0,
|
||||||
"date": r.GetDateTime("date").Time().Unix(),
|
"date": r.GetDateTime("date").Time().Unix(),
|
||||||
"created": r.GetDateTime("created").Time().Unix(),
|
"created": r.GetDateTime("created").Time().Unix(),
|
||||||
"public": r.GetBool("public"),
|
"public": r.GetBool("public"),
|
||||||
"thumbnail": thumbnail,
|
"thumbnail": thumbnail,
|
||||||
"gpx": r.GetString("gpx"),
|
"gpx": r.GetString("gpx"),
|
||||||
"tags": tags,
|
"tags": tags,
|
||||||
"polyline": polyline,
|
// "polyline": polyline,
|
||||||
|
"domain": domain,
|
||||||
|
"iri": r.GetString("iri"),
|
||||||
"_geo": map[string]float64{
|
"_geo": map[string]float64{
|
||||||
"lat": r.GetFloat("lat"),
|
"lat": r.GetFloat("lat"),
|
||||||
"lng": r.GetFloat("lon"),
|
"lng": r.GetFloat("lon"),
|
||||||
@@ -66,6 +89,9 @@ func documentFromTrailRecord(app core.App, r *core.Record, author *core.Record,
|
|||||||
|
|
||||||
if includeShares {
|
if includeShares {
|
||||||
document["shares"] = []string{}
|
document["shares"] = []string{}
|
||||||
|
document["likes"] = []string{}
|
||||||
|
document["like_count"] = 0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return document, nil
|
return document, nil
|
||||||
@@ -109,28 +135,124 @@ func getPolyline(app core.App, r *core.Record) (string, error) {
|
|||||||
return string(polyline.EncodeCoords(coordinates)), nil
|
return string(polyline.EncodeCoords(coordinates)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func documentFromListRecord(r *core.Record, includeShares bool) map[string]interface{} {
|
func documentFromListRecord(r *core.Record, author *core.Record, includeShares bool) (map[string]interface{}, error) {
|
||||||
|
|
||||||
|
totalElevationGain := 0.0
|
||||||
|
totalElevationLoss := 0.0
|
||||||
|
totalDistance := 0.0
|
||||||
|
totalDuration := 0.0
|
||||||
|
trails := len(r.GetStringSlice("trails"))
|
||||||
|
|
||||||
|
if r.GetString("iri") != "" {
|
||||||
|
doc, err := documentFromRemoteRecord(r, "lists")
|
||||||
|
if err == nil {
|
||||||
|
totalElevationGain = doc["elevation_gain"].(float64)
|
||||||
|
totalElevationLoss = doc["elevation_loss"].(float64)
|
||||||
|
totalDistance = doc["distance"].(float64)
|
||||||
|
totalDuration = doc["duration"].(float64)
|
||||||
|
|
||||||
|
trails = int(doc["trails"].(float64))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
allTrails := r.ExpandedAll("trails")
|
||||||
|
|
||||||
|
for _, t := range allTrails {
|
||||||
|
totalElevationGain += t.GetFloat("elevation_gain")
|
||||||
|
totalElevationLoss += t.GetFloat("elevation_loss")
|
||||||
|
totalDistance += t.GetFloat("distance")
|
||||||
|
totalDuration += t.GetFloat("duration")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document := map[string]interface{}{
|
document := map[string]interface{}{
|
||||||
"id": r.Id,
|
"id": r.Id,
|
||||||
"author": r.GetString("author"),
|
"author": author.Id,
|
||||||
"name": r.GetString("name"),
|
"author_name": author.GetString("username"),
|
||||||
"description": r.GetString("description"),
|
"author_avatar": author.GetString("icon"),
|
||||||
"public": r.GetBool("public"),
|
"avatar": r.GetString("avatar"),
|
||||||
"created": r.GetDateTime("created").Time().Unix(),
|
"name": r.GetString("name"),
|
||||||
"trails": r.GetStringSlice("trails"),
|
"description": r.GetString("description"),
|
||||||
|
"elevation_gain": totalElevationGain,
|
||||||
|
"elevation_loss": totalElevationLoss,
|
||||||
|
"distance": totalDistance,
|
||||||
|
"duration": totalDuration,
|
||||||
|
"public": r.GetBool("public"),
|
||||||
|
"created": r.GetDateTime("created").Time().Unix(),
|
||||||
|
"trails": trails,
|
||||||
|
"iri": r.GetString("iri"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if includeShares {
|
if includeShares {
|
||||||
document["shares"] = []string{}
|
document["shares"] = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return document
|
return document, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func documentFromRemoteRecord(r *core.Record, index string) (map[string]interface{}, error) {
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
if r.GetString("iri") == "" {
|
||||||
|
return nil, fmt.Errorf("record has no iri")
|
||||||
|
}
|
||||||
|
|
||||||
|
iri := r.GetString("iri")
|
||||||
|
|
||||||
|
url, err := url.Parse(iri)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteRecordId := path.Base(url.Path)
|
||||||
|
|
||||||
|
searchURL := fmt.Sprintf("%s://%s/api/v1/search/%s", url.Scheme, url.Host, index)
|
||||||
|
body := []byte(fmt.Sprintf(`{"q": "%s"}`, remoteRecordId))
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", searchURL, bytes.NewBuffer(body))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("failed to fetch remote record: received status %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
respBytes, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var searchResponse meilisearch.SearchResponse
|
||||||
|
json.Unmarshal(respBytes, &searchResponse)
|
||||||
|
|
||||||
|
if len(searchResponse.Hits) == 0 {
|
||||||
|
return nil, fmt.Errorf("no documents in result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
document, ok := searchResponse.Hits[0].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected document format")
|
||||||
|
}
|
||||||
|
return document, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IndexTrail(app core.App, r *core.Record, author *core.Record, client meilisearch.ServiceManager) error {
|
func IndexTrail(app core.App, r *core.Record, author *core.Record, client meilisearch.ServiceManager) error {
|
||||||
errs := app.ExpandRecord(r, []string{"tags"}, nil)
|
errs := app.ExpandRecord(r, []string{"tags"}, nil)
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return fmt.Errorf("failed to expand: %v", errs)
|
return fmt.Errorf("failed to expand tags: %v", errs)
|
||||||
|
}
|
||||||
|
errs = app.ExpandRecord(r, []string{"category"}, nil)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return fmt.Errorf("failed to expand category: %v", errs)
|
||||||
}
|
}
|
||||||
doc, err := documentFromTrailRecord(app, r, author, true)
|
doc, err := documentFromTrailRecord(app, r, author, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -148,10 +270,14 @@ func IndexTrail(app core.App, r *core.Record, author *core.Record, client meilis
|
|||||||
func UpdateTrail(app core.App, r *core.Record, author *core.Record, client meilisearch.ServiceManager) error {
|
func UpdateTrail(app core.App, r *core.Record, author *core.Record, client meilisearch.ServiceManager) error {
|
||||||
errs := app.ExpandRecord(r, []string{"tags"}, nil)
|
errs := app.ExpandRecord(r, []string{"tags"}, nil)
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return fmt.Errorf("failed to expand: %v", errs)
|
return fmt.Errorf("failed to expand tags: %v", errs)
|
||||||
|
}
|
||||||
|
errs = app.ExpandRecord(r, []string{"category"}, nil)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return fmt.Errorf("failed to expand category: %v", errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
doc, err := documentFromTrailRecord(app, r, author, true)
|
doc, err := documentFromTrailRecord(app, r, author, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -177,20 +303,49 @@ func UpdateTrailShares(trailId string, shares []string, client meilisearch.Servi
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IndexList(r *core.Record, client meilisearch.ServiceManager) error {
|
func UpdateTrailLikes(trailId string, likes []string, client meilisearch.ServiceManager) error {
|
||||||
documents := []map[string]interface{}{documentFromListRecord(r, true)}
|
documents := []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"id": trailId,
|
||||||
|
"like_count": len(likes),
|
||||||
|
"likes": likes,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if _, err := client.Index("trails").UpdateDocuments(documents); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := client.Index("lists").AddDocuments(documents); err != nil {
|
func IndexList(app core.App, r *core.Record, author *core.Record, client meilisearch.ServiceManager) error {
|
||||||
|
errs := app.ExpandRecord(r, []string{"trails"}, nil)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return fmt.Errorf("failed to expand trails: %v", errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
documents, err := documentFromListRecord(r, author, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err = client.Index("lists").AddDocuments(documents); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateList(r *core.Record, client meilisearch.ServiceManager) error {
|
func UpdateList(app core.App, r *core.Record, author *core.Record, client meilisearch.ServiceManager) error {
|
||||||
documents := documentFromListRecord(r, false)
|
errs := app.ExpandRecord(r, []string{"trails"}, nil)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return fmt.Errorf("failed to expand trails: %v", errs)
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := client.Index("lists").UpdateDocuments(documents); err != nil {
|
documents, err := documentFromListRecord(r, author, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = client.Index("lists").UpdateDocuments(documents); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,15 @@ import (
|
|||||||
type NotificationType string
|
type NotificationType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TrailCreate NotificationType = "trail_create"
|
TrailShare NotificationType = "trail_share"
|
||||||
TrailShare NotificationType = "trail_share"
|
ListShare NotificationType = "list_share"
|
||||||
ListCreate NotificationType = "list_create"
|
NewFollower NotificationType = "new_follower"
|
||||||
ListShare NotificationType = "list_share"
|
TrailComment NotificationType = "trail_comment"
|
||||||
NewFollower NotificationType = "new_follower"
|
TrailLike NotificationType = "trail_like"
|
||||||
TrailComment NotificationType = "trail_comment"
|
SummitLogCreate NotificationType = "summit_log_create"
|
||||||
|
CommentMention NotificationType = "comment_mention"
|
||||||
|
TrailMention NotificationType = "trail_mention"
|
||||||
|
SummitLogMention NotificationType = "summit_log_mention"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Notification struct {
|
type Notification struct {
|
||||||
@@ -54,11 +57,14 @@ func getNotificationPermissions(app core.App, user string, notificationType Noti
|
|||||||
return &settingsForType, nil
|
return &settingsForType, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendNotification(app core.App, notification Notification, recipient string) error {
|
func SendNotification(app core.App, notification Notification, recipient *core.Record) error {
|
||||||
if notification.Author == recipient {
|
if notification.Author == recipient.Id {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
permissions, err := getNotificationPermissions(app, recipient, notification.Type)
|
if !recipient.GetBool("isLocal") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
permissions, err := getNotificationPermissions(app, recipient.GetString("user"), notification.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -73,7 +79,7 @@ func SendNotification(app core.App, notification Notification, recipient string)
|
|||||||
n.Set("type", string(notification.Type))
|
n.Set("type", string(notification.Type))
|
||||||
n.Set("metadata", notification.Metadata)
|
n.Set("metadata", notification.Metadata)
|
||||||
n.Set("seen", notification.Seen)
|
n.Set("seen", notification.Seen)
|
||||||
n.Set("recipient", recipient)
|
n.Set("recipient", recipient.Id)
|
||||||
n.Set("author", notification.Author)
|
n.Set("author", notification.Author)
|
||||||
|
|
||||||
if err := app.Save(n); err != nil {
|
if err := app.Save(n); err != nil {
|
||||||
@@ -82,15 +88,15 @@ func SendNotification(app core.App, notification Notification, recipient string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if permissions.Email {
|
if permissions.Email {
|
||||||
recipientUser, err := app.FindRecordById("users", recipient)
|
recipientActor, err := app.FindRecordById("activitypub_actors", recipient.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
authorUser, err := app.FindRecordById("users", notification.Author)
|
authorActor, err := app.FindRecordById("activitypub_actors", notification.Author)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
html, err := GenerateHTML(app.Settings().Meta.AppURL, recipientUser.GetString("username"), authorUser.GetString("username"), notification.Type, notification.Metadata)
|
html, err := GenerateHTML(app.Settings().Meta.AppURL, recipientActor.GetString("username"), authorActor.GetString("username"), notification.Type, notification.Metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -100,27 +106,12 @@ func SendNotification(app core.App, notification Notification, recipient string)
|
|||||||
Address: app.Settings().Meta.SenderAddress,
|
Address: app.Settings().Meta.SenderAddress,
|
||||||
Name: app.Settings().Meta.SenderName,
|
Name: app.Settings().Meta.SenderName,
|
||||||
},
|
},
|
||||||
To: []mail.Address{{Address: recipientUser.Email()}},
|
To: []mail.Address{{Address: recipientActor.Email()}},
|
||||||
Subject: "wanderer - New Notification",
|
Subject: "wanderer - New Notification",
|
||||||
HTML: html,
|
HTML: html,
|
||||||
}
|
}
|
||||||
|
|
||||||
app.NewMailClient().Send(message)
|
return app.NewMailClient().Send(message)
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SendNotificationToFollowers(app core.App, notification Notification) error {
|
|
||||||
followers, err := app.FindRecordsByFilter("follows", "followee={:user}", "", -1, 0, dbx.Params{"user": notification.Author})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range followers {
|
|
||||||
recipient := f.GetString("follower")
|
|
||||||
SendNotification(app, notification, recipient)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user