fix webfinger routing, create group listing api, web homepage with groups list

This commit is contained in:
william Murphy 2019-11-17 19:31:58 -06:00
parent 5407d1cfe1
commit 45f25bdc6a
11 changed files with 115 additions and 146 deletions

View file

@ -29,7 +29,11 @@ app.set('port', process.env.PORT || PORT)
app.set('port-https', process.env.PORT_HTTPS || PORT_HTTPS)
app.use(morgan('combined'))
app.use(history({
index: '/web/index.html'
index: '/web/index.html',
rewrites: [
// do not redirect webfinger et c.
{ from: /^\/\.well-known\//, to: context => context.request.originalUrl }
]
}))
app.use(bodyParser.json({
type: pub.consts.jsonldTypes

13
package-lock.json generated
View file

@ -2645,8 +2645,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
@ -3061,8 +3060,7 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
@ -3118,7 +3116,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -3162,14 +3159,12 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
}
}
},

View file

@ -1,7 +1,7 @@
{
"name": "guppe",
"version": "0.0.1",
"description": "Decentralized social groups with ActivityPub, NodeJS, Express, and Mongodb",
"description": "Decentralized social groups with ActivityPub, NodeJS, Express, Vue, and Mongodb",
"main": "index.js",
"dependencies": {
"body-parser": "^1.18.3",

View file

@ -4,6 +4,30 @@ const router = express.Router()
const pub = require('../pub')
const net = require('../net')
// list active groups
router.get('/', net.validators.jsonld, function (req, res) {
const db = req.app.get('db')
db.collection('streams')
.aggregate([
{ $limit: 10000 }, // don't traverse the entire history
{ $match: { type: 'Announce' } },
{ $group: { _id: '$actor', postCount: { $sum: 1 } } },
{ $lookup: { from: 'objects', localField: '_id', foreignField: 'id', as: 'actor' } },
// merge joined actor up
{ $replaceRoot: { newRoot: { $mergeObjects: [{ $arrayElemAt: ['$actor', 0] }, '$$ROOT'] } } },
{ $project: { postCount: 1, preferredUsername: 1 } }
])
.sort({ postCount: -1 })
.limit(Number.parseInt(req.query.n) || 20)
.toArray()
.then(groups => { console.log(JSON.stringify(groups)); return groups })
.then(groups => res.json(groups))
.catch(err => {
console.log(err.message)
return res.status(500).send()
})
})
router.get('/:name', net.validators.jsonld, function (req, res) {
const name = req.params.name
if (!name) {

47
web/package-lock.json generated
View file

@ -3026,8 +3026,7 @@
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
"dev": true,
"optional": true
"dev": true
},
"coa": {
"version": "2.0.2",
@ -5634,8 +5633,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
@ -5656,14 +5654,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -5678,20 +5674,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@ -5808,8 +5801,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@ -5821,7 +5813,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -5836,7 +5827,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -5844,14 +5834,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -5870,7 +5858,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -5951,8 +5938,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@ -5964,7 +5950,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -6050,8 +6035,7 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
@ -6087,7 +6071,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -6107,7 +6090,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -6151,14 +6133,12 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
}
}
},
@ -10214,8 +10194,7 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
"integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=",
"dev": true,
"optional": true
"dev": true
},
"rx-lite-aggregates": {
"version": "4.0.8",

View file

@ -6,11 +6,11 @@
</div> -->
<div class="w3-bar w3-black w3-card">&nbsp;</div>
<div class="w3-row">
<div class="w3-col s0 m2">&nbsp;</div>
<div class="w3-col s12 m8 w3-content">
<div class="w3-col s0 m1 l2">&nbsp;</div>
<div class="w3-col s12 m10 l8 w3-content">
<router-view/>
</div>
<div class="w3-col s0 m2">&nbsp;</div>
<div class="w3-col s0 m1 l2">&nbsp;</div>
</div>
<footer class="w3-container w3-padding-64 w3-center w3-opacity w3-light-grey w3-xlarge">
<a href="https://github.com/wmurphyrd/guppe"><i class="fa fa-github w3-hover-opacity"></i></a>
@ -23,7 +23,6 @@
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>

View file

@ -1,59 +0,0 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-unit-mocha" target="_blank" rel="noopener">unit-mocha</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

View file

@ -13,19 +13,11 @@ export default new Router({
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
},
{
path: '/u/:name',
name: 'profile',
component: Profile,
props: true,
props: true
}
]
})

View file

@ -1,5 +0,0 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>

View file

@ -1,40 +1,75 @@
<template>
<div class="w3-container">
<img alt="Guppe logo" src="/f/guppe.png">
<h1>Guppe Groups</h1>
<div class="w3-center">
<img alt="Guppe logo" src="/f/guppe.png">
</div>
<h1 class="w3-center">Guppe Groups</h1>
<p>
Guppe brings social groups to the fediverse &mdash; making it easy to connect and meet new
people based on shared
interests without the maniuplation of your attention to maximize ad revenue nor the
walled garden lock-in of capitalist social media.
Guppe brings social groups to the fediverse &mdash; making it easy to connect and meet new
people based on shared
interests without the maniuplation of your attention to maximize ad revenue nor the
walled garden lock-in of capitalist social media.
</p>
<h2 class="w3-center">How does Guppe work?</h2>
<p>
Guppe groups look like regular users you can interact with using your existing account on any
ActivityPub service, but they automatically share anything you send them with all of their followers.
</p>
<h2>How does Guppe work?</h2>
<ol>
<li>Follow a user on @gup.pe to join that group</li>
<li>Mention a user on @gup.pe to share a post with everyone in the group</li>
<li>New groups are created on demand, just search for @YourGroupNameHere@gup.pe and it will show up</li>
<li>Visit a @gup.pe user profile to see the group history</li>
<li>Follow a group on @gup.pe to join that group</li>
<li>Mention a group on @gup.pe to share a post with everyone in the group</li>
<li>New groups are created on demand, just search for or mention @YourGroupNameHere@gup.pe and it will show up</li>
<li>Visit a @gup.pe group profile to see the group history</li>
</ol>
<p>
A Guppe Group has its own account and profile.
This server-2-server ActivityPub implementation adds decentralized,
federaded "groups" support across all ActivityPub compliant social media networks.
Users join groups by following group-type actors on Guppe servers and contribute t
groups by mentioning those same actors in a post. Guppe group actors will
automatically forward posts they receive to all group members so that everyone in the
group sees any post made to the group. Guppe group actors' profiles (e.g. outboxes) also
serve as a group discussion history.
</p>
<h2 class="w3-center">Active Groups</h2>
<div class="profile-grid w3-margin-bottom w3-mobile">
<div v-for="group of groups" class="w3-card" :key="group._id">
<Profile :name="group.preferredUsername" :post-limit="3"
class="profile"/>
<router-link :to="`/u/${group.preferredUsername}`">More...</router-link>
</div>
</div>
</div>
</template>
<script>
// @ is an alias to /src
// import HelloWorld from '@/components/HelloWorld.vue'
import Profile from '@/views/Profile.vue'
export default {
name: 'home',
components: {
Profile
},
data() {
return {
groups: [],
error: null
}
},
created () {
window.fetch(`/u/`, {
method: 'get',
headers: {
accept: 'application/json'
}
}).then(res => res.json())
.then(json => {
this.groups = json
})
.catch(err => this.error = err.message)
}
}
</script>
<style scoped>
.profile {
width: 300px;
}
.profile-grid {
display: grid;
grid-gap: 15px;
grid-template-columns: auto auto;
justify-content: space-evenly;
}
</style>

View file

@ -1,6 +1,6 @@
<template>
<div class="w3-container w3-content w3-center w3-padding-32">
<img class="profile-main" :src="groupProfileSrc">
<img class="w3-image" :src="groupProfileSrc">
<h2 class="w3-wide">{{ actor.preferredUsername }}</h2>
<p class="w3-opacity"><i>{{ actor.summary }}</i></p>
<p class="w3-left-align">To join {{ actor.preferredUsername }}, enter your handle below and you'll be
@ -43,6 +43,10 @@ export default {
name: {
type: String,
required: true,
},
postLimit: {
type: Number,
default: 20
}
},
data () {
@ -124,6 +128,7 @@ export default {
.then(outbox => {
this.stream = outbox.orderedItems // || fetch page
.filter(act => act.type === 'Announce')
.slice(0, this.postLimit)
})
.catch(err => this.error = err.message)
}