You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
5.3 KiB
Go

// apcore is a server framework for implementing an ActivityPub application.
// Copyright (C) 2019 Cory Slep
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package main
import (
"context"
"net/url"
"github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab"
"github.com/go-fed/apcore/app"
"github.com/go-fed/apcore/models"
"github.com/go-fed/apcore/util"
)
func getLatestPublicNotes(ctx context.Context, db app.Database) (notes []vocab.Type, err error) {
return getNotes(ctx, db, `WITH local_notes AS(
SELECT payload, create_time FROM %[1]slocal_data
WHERE payload->>'type' = 'Note' AND (
payload->'to' ? 'https://www.w3.org/ns/activitystreams#Public'
OR payload->'cc' ? 'https://www.w3.org/ns/activitystreams#Public')
), fed_notes AS (
SELECT payload, create_time FROM %[1]sfed_data
WHERE payload->>'type' = 'Note' AND (
payload->'to' ? 'https://www.w3.org/ns/activitystreams#Public'
OR payload->'cc' ? 'https://www.w3.org/ns/activitystreams#Public')
), unioned AS (
SELECT payload, create_time FROM local_notes
UNION
SELECT payload, create_time FROM fed_notes
), deduped AS (
SELECT
DISTINCT ON (payload->'id') payload,
create_time
FROM unioned
ORDER BY payload->'id'
)
SELECT payload FROM deduped
ORDER BY create_time DESC
LIMIT 10`)
}
func getLatestNotesAndMyPrivateNotes(ctx context.Context, db app.Database, userIRI string) (notes []vocab.Type, err error) {
return getNotes(ctx, db, `WITH local_notes AS(
SELECT payload, create_time FROM %[1]slocal_data
WHERE payload->>'type' = 'Note' AND (
payload->'to' ? 'https://www.w3.org/ns/activitystreams#Public'
OR payload->'cc' ? 'https://www.w3.org/ns/activitystreams#Public'
OR payload->>'attributedTo' = $1
OR payload->'to' ? $1
OR payload->'cc' ? $1)
), fed_notes AS (
SELECT payload, create_time FROM %[1]sfed_data
WHERE payload->>'type' = 'Note' AND (
payload->'to' ? 'https://www.w3.org/ns/activitystreams#Public'
OR payload->'cc' ? 'https://www.w3.org/ns/activitystreams#Public'
OR payload->>'attributedTo' = $1
OR payload->'to' ? $1
OR payload->'cc' ? $1)
), unioned AS (
SELECT payload, create_time FROM local_notes
UNION
SELECT payload, create_time FROM fed_notes
), deduped AS (
SELECT
DISTINCT ON (payload->'id') payload,
create_time
FROM unioned
ORDER BY payload->'id'
)
SELECT payload
FROM deduped
ORDER BY create_time DESC
LIMIT 10`,
userIRI)
}
func getNotes(ctx context.Context, db app.Database, sql string, data ...interface{}) (notes []vocab.Type, err error) {
c := util.Context{ctx}
var rz *streams.TypeResolver
rz, err = streams.NewTypeResolver(func(c context.Context, note vocab.ActivityStreamsNote) error {
notes = append(notes, note)
return nil
})
if err != nil {
return
}
txb := db.Begin()
txb.Query(sql,
func(r app.SingleRow) error {
var v models.ActivityStreams
if err := r.Scan(&v); err != nil {
return err
}
return rz.Resolve(c.Context, v.Type)
},
data...)
err = txb.Do(c)
return
}
func getUsers(ctx context.Context, db app.Database) (ppl []vocab.Type, err error) {
c := util.Context{ctx}
var rz *streams.TypeResolver
rz, err = streams.NewTypeResolver(func(c context.Context, pn vocab.ActivityStreamsPerson) error {
ppl = append(ppl, pn)
return nil
})
if err != nil {
return
}
txb := db.Begin()
txb.Query(`SELECT actor FROM %[1]susers
WHERE actor->>'type' = 'Person'
ORDER BY create_time DESC`,
func(r app.SingleRow) error {
var v models.ActivityStreams
if err := r.Scan(&v); err != nil {
return err
}
return rz.Resolve(c.Context, v.Type)
})
err = txb.Do(c)
return
}
func getNoteIsReadable(ctx util.Context, db app.Database, noteID, userID *url.URL) (legible /*lol*/ bool, err error) {
txb := db.Begin()
txb.Query(`SELECT EXISTS (
SELECT create_time FROM %[1]slocal_data
WHERE payload->>'type' = 'Note' AND (
payload->'to' ? 'https://www.w3.org/ns/activitystreams#Public'
OR payload->'cc' ? 'https://www.w3.org/ns/activitystreams#Public'
OR payload->>'attributedTo' = $2
OR payload->'to' ? $2
OR payload->'cc' ? $2)
AND payload->>'id' = $1)`,
func(r app.SingleRow) error {
return r.Scan(&legible)
},
noteID.String(), userID.String())
err = txb.Do(ctx)
return
}
func getNoteIsPublic(ctx util.Context, db app.Database, noteID *url.URL) (pub bool, err error) {
txb := db.Begin()
txb.Query(`SELECT EXISTS (
SELECT create_time FROM %[1]slocal_data
WHERE payload->>'type' = 'Note' AND (
payload->'to' ? 'https://www.w3.org/ns/activitystreams#Public'
OR payload->'cc' ? 'https://www.w3.org/ns/activitystreams#Public')
AND payload->>'id' = $1)`,
func(r app.SingleRow) error {
return r.Scan(&pub)
},
noteID.String())
err = txb.Do(ctx)
return
}