Update npm dependencies
Problem: Our dependencies are falling behind and it'd be nice to have them up-to-date. The only big update it that Common-Good upgraded to the latest version of Prettier. Solution: Update them!
This commit is contained in:
parent
8c71d93ab3
commit
32465e5983
|
@ -2,15 +2,15 @@ module.exports = {
|
|||
env: {
|
||||
commonjs: true,
|
||||
es6: true,
|
||||
node: true
|
||||
node: true,
|
||||
},
|
||||
extends: "eslint:recommended",
|
||||
globals: {
|
||||
Atomics: "readonly",
|
||||
SharedArrayBuffer: "readonly"
|
||||
SharedArrayBuffer: "readonly",
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018
|
||||
ecmaVersion: 2018,
|
||||
},
|
||||
rules: {}
|
||||
rules: {},
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
|
@ -22,7 +22,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@fraction/base16-css": "^1.1.0",
|
||||
"@fraction/flotilla": "^4.0.1",
|
||||
"@fraction/flotilla": "^4.0.0",
|
||||
"@koa/router": "^8.0.0",
|
||||
"debug": "^4.1.1",
|
||||
"env-paths": "^2.2.0",
|
||||
"highlight.js": "^9.18.1",
|
||||
|
@ -31,12 +32,11 @@
|
|||
"koa": "^2.7.0",
|
||||
"koa-body": "^4.1.0",
|
||||
"koa-mount": "^4.0.0",
|
||||
"koa-router": "^7.4.0",
|
||||
"koa-static": "^5.0.0",
|
||||
"lodash": "^4.17.11",
|
||||
"markdown-it": "^8.4.2",
|
||||
"open": "7.0.0",
|
||||
"pretty-ms": "^5.0.0",
|
||||
"open": "^7.0.3",
|
||||
"pretty-ms": "^6.0.0",
|
||||
"pull-paramap": "^1.2.2",
|
||||
"pull-sort": "^1.0.2",
|
||||
"pull-stream": "^3.6.12",
|
||||
|
@ -44,19 +44,19 @@
|
|||
"sharp": "^0.23.0",
|
||||
"ssb-client": "^4.9.0",
|
||||
"ssb-config": "^3.4.4",
|
||||
"ssb-markdown": "^6.0.4",
|
||||
"ssb-markdown": "^6.0.5",
|
||||
"ssb-mentions": "^0.5.2",
|
||||
"ssb-msgs": "^5.2.0",
|
||||
"ssb-ref": "^2.13.9",
|
||||
"ssb-tangle": "^1.0.1",
|
||||
"ssb-thread-schema": "^1.1.1",
|
||||
"yargs": "^15.3.0"
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"changelog-version": "^1.0.1",
|
||||
"common-good": "^1.1.20",
|
||||
"husky": "^3.0.5",
|
||||
"mkdirp": "^0.5.1",
|
||||
"common-good": "^2.0.2",
|
||||
"husky": "^4.0.0",
|
||||
"mkdirp": "^1.0.0",
|
||||
"nodemon": "^2.0.2",
|
||||
"stylelint-config-recommended": "^3.0.0"
|
||||
},
|
||||
|
|
12
src/cli.js
12
src/cli.js
|
@ -14,33 +14,33 @@ module.exports = (presets, defaultConfigFile) =>
|
|||
describe:
|
||||
"Automatically open app in web browser. Use --no-open to disable.",
|
||||
default: _.get(presets, "open", true),
|
||||
type: "boolean"
|
||||
type: "boolean",
|
||||
})
|
||||
.options("offline", {
|
||||
describe:
|
||||
"Don't try to connect to scuttlebutt peers or pubs. This can be changed on the 'settings' page while Oasis is running.",
|
||||
default: _.get(presets, "offline", false),
|
||||
type: "boolean"
|
||||
type: "boolean",
|
||||
})
|
||||
.options("host", {
|
||||
describe: "Hostname for web app to listen on",
|
||||
default: _.get(presets, "host", "localhost"),
|
||||
type: "string"
|
||||
type: "string",
|
||||
})
|
||||
.options("port", {
|
||||
describe: "Port for web app to listen on",
|
||||
default: _.get(presets, "port", 3000),
|
||||
type: "number"
|
||||
type: "number",
|
||||
})
|
||||
.options("public", {
|
||||
describe:
|
||||
"Assume Oasis is being hosted publicly, disable HTTP POST and redact messages from people who haven't given consent for public web hosting.",
|
||||
default: _.get(presets, "public", false),
|
||||
type: "boolean"
|
||||
type: "boolean",
|
||||
})
|
||||
.options("debug", {
|
||||
describe: "Use verbose output for debugging",
|
||||
default: _.get(presets, "debug", false),
|
||||
type: "boolean"
|
||||
type: "boolean",
|
||||
})
|
||||
.epilog(`The defaults can be configured in ${defaultConfigFile}.`).argv;
|
||||
|
|
|
@ -13,7 +13,7 @@ module.exports = ({ host, port, middleware }) => {
|
|||
const app = new Koa();
|
||||
module.exports = app;
|
||||
|
||||
app.on("error", err => {
|
||||
app.on("error", (err) => {
|
||||
// Output full error objects
|
||||
err.message = err.stack;
|
||||
console.error(err);
|
||||
|
@ -32,7 +32,7 @@ module.exports = ({ host, port, middleware }) => {
|
|||
"img-src 'self'",
|
||||
"form-action 'self'",
|
||||
"media-src 'self'",
|
||||
"style-src 'self' 'unsafe-inline'"
|
||||
"style-src 'self' 'unsafe-inline'",
|
||||
].join("; ");
|
||||
|
||||
// Disallow scripts.
|
||||
|
@ -69,6 +69,6 @@ module.exports = ({ host, port, middleware }) => {
|
|||
}
|
||||
});
|
||||
|
||||
middleware.forEach(m => app.use(m));
|
||||
middleware.forEach((m) => app.use(m));
|
||||
app.listen({ host, port });
|
||||
};
|
||||
|
|
156
src/index.js
156
src/index.js
|
@ -66,12 +66,12 @@ these settings the default. See the readme for details.`);
|
|||
|
||||
const oasisCheckPath = "/.well-known/oasis";
|
||||
|
||||
process.on("uncaughtException", function(err) {
|
||||
process.on("uncaughtException", function (err) {
|
||||
// This isn't `err.code` because TypeScript doesn't like that.
|
||||
if (err["code"] === "EADDRINUSE") {
|
||||
nodeHttp.get(url + oasisCheckPath, res => {
|
||||
nodeHttp.get(url + oasisCheckPath, (res) => {
|
||||
let rawData = "";
|
||||
res.on("data", chunk => {
|
||||
res.on("data", (chunk) => {
|
||||
rawData += chunk;
|
||||
});
|
||||
res.on("end", () => {
|
||||
|
@ -123,7 +123,7 @@ const { nav, ul, li, a } = require("hyperaxe");
|
|||
const open = require("open");
|
||||
const pull = require("pull-stream");
|
||||
const requireStyle = require("require-style");
|
||||
const router = require("koa-router")();
|
||||
const router = require("@koa/router")();
|
||||
const ssbMentions = require("ssb-mentions");
|
||||
const ssbRef = require("ssb-ref");
|
||||
const isSvg = require("is-svg");
|
||||
|
@ -138,7 +138,7 @@ const cooler = ssb({ offline: config.offline });
|
|||
|
||||
const { about, blob, friend, meta, post, vote } = require("./models")({
|
||||
cooler,
|
||||
isPublic: config.public
|
||||
isPublic: config.public,
|
||||
});
|
||||
|
||||
const {
|
||||
|
@ -162,7 +162,7 @@ const {
|
|||
setLanguage,
|
||||
settingsView,
|
||||
topicsView,
|
||||
summaryView
|
||||
summaryView,
|
||||
} = require("./views");
|
||||
|
||||
let sharp;
|
||||
|
@ -178,11 +178,11 @@ const defaultTheme = "atelier-sulphurPool-light".toLowerCase();
|
|||
const readmePath = path.join(__dirname, "..", "README.md");
|
||||
const packagePath = path.join(__dirname, "..", "package.json");
|
||||
|
||||
fs.promises.readFile(readmePath, "utf8").then(text => {
|
||||
fs.promises.readFile(readmePath, "utf8").then((text) => {
|
||||
config.readme = text;
|
||||
});
|
||||
|
||||
fs.promises.readFile(packagePath, "utf8").then(text => {
|
||||
fs.promises.readFile(packagePath, "utf8").then((text) => {
|
||||
config.version = JSON.parse(text).version;
|
||||
});
|
||||
|
||||
|
@ -207,21 +207,21 @@ router
|
|||
ctx.assert(ssbRef.isFeedId(message), 400, "Invalid feed link");
|
||||
return next();
|
||||
})
|
||||
.get("/", async ctx => {
|
||||
.get("/", async (ctx) => {
|
||||
ctx.redirect("/mentions");
|
||||
})
|
||||
.get("/robots.txt", ctx => {
|
||||
.get("/robots.txt", (ctx) => {
|
||||
ctx.body = "User-agent: *\nDisallow: /";
|
||||
})
|
||||
.get(oasisCheckPath, ctx => {
|
||||
.get(oasisCheckPath, (ctx) => {
|
||||
ctx.body = "oasis";
|
||||
})
|
||||
.get("/public/popular/:period", async ctx => {
|
||||
.get("/public/popular/:period", async (ctx) => {
|
||||
const { period } = ctx.params;
|
||||
const publicPopular = async ({ period }) => {
|
||||
const messages = await post.popular({ period });
|
||||
|
||||
const option = somePeriod => {
|
||||
const option = (somePeriod) => {
|
||||
const lowerPeriod = somePeriod.toLowerCase();
|
||||
return li(
|
||||
period === lowerPeriod
|
||||
|
@ -236,30 +236,30 @@ router
|
|||
|
||||
return popularView({
|
||||
messages,
|
||||
prefix
|
||||
prefix,
|
||||
});
|
||||
};
|
||||
ctx.body = await publicPopular({ period });
|
||||
})
|
||||
.get("/public/latest", async ctx => {
|
||||
.get("/public/latest", async (ctx) => {
|
||||
const messages = await post.latest();
|
||||
ctx.body = await latestView({ messages });
|
||||
})
|
||||
.get("/public/latest/extended", async ctx => {
|
||||
.get("/public/latest/extended", async (ctx) => {
|
||||
const messages = await post.latestExtended();
|
||||
ctx.body = await extendedView({ messages });
|
||||
})
|
||||
.get("/public/latest/topics", async ctx => {
|
||||
.get("/public/latest/topics", async (ctx) => {
|
||||
const messages = await post.latestTopics();
|
||||
ctx.body = await topicsView({ messages });
|
||||
})
|
||||
.get("/public/latest/summaries", async ctx => {
|
||||
.get("/public/latest/summaries", async (ctx) => {
|
||||
const messages = await post.latestSummaries();
|
||||
ctx.body = await summaryView({ messages });
|
||||
})
|
||||
.get("/author/:feed", async ctx => {
|
||||
.get("/author/:feed", async (ctx) => {
|
||||
const { feed } = ctx.params;
|
||||
const author = async feedId => {
|
||||
const author = async (feedId) => {
|
||||
const description = await about.description(feedId);
|
||||
const name = await about.name(feedId);
|
||||
const image = await about.image(feedId);
|
||||
|
@ -274,12 +274,12 @@ router
|
|||
name,
|
||||
description,
|
||||
avatarUrl,
|
||||
relationship
|
||||
relationship,
|
||||
});
|
||||
};
|
||||
ctx.body = await author(feed);
|
||||
})
|
||||
.get("/search/", async ctx => {
|
||||
.get("/search/", async (ctx) => {
|
||||
let { query } = ctx.query;
|
||||
|
||||
if (isMsg(query)) {
|
||||
|
@ -305,7 +305,7 @@ router
|
|||
|
||||
ctx.body = await searchView({ messages, query });
|
||||
})
|
||||
.get("/inbox", async ctx => {
|
||||
.get("/inbox", async (ctx) => {
|
||||
const inbox = async () => {
|
||||
const messages = await post.inbox();
|
||||
|
||||
|
@ -313,13 +313,13 @@ router
|
|||
};
|
||||
ctx.body = await inbox();
|
||||
})
|
||||
.get("/hashtag/:hashtag", async ctx => {
|
||||
.get("/hashtag/:hashtag", async (ctx) => {
|
||||
const { hashtag } = ctx.params;
|
||||
const messages = await post.fromHashtag(hashtag);
|
||||
|
||||
ctx.body = await hashtagView({ hashtag, messages });
|
||||
})
|
||||
.get("/theme.css", ctx => {
|
||||
.get("/theme.css", (ctx) => {
|
||||
const theme = ctx.cookies.get("theme") || defaultTheme;
|
||||
|
||||
const packageName = "@fraction/base16-css";
|
||||
|
@ -327,7 +327,7 @@ router
|
|||
ctx.type = "text/css";
|
||||
ctx.body = requireStyle(filePath);
|
||||
})
|
||||
.get("/profile/", async ctx => {
|
||||
.get("/profile/", async (ctx) => {
|
||||
const myFeedId = await meta.myFeedId();
|
||||
|
||||
const description = await about.description(myFeedId);
|
||||
|
@ -344,20 +344,20 @@ router
|
|||
name,
|
||||
description,
|
||||
avatarUrl,
|
||||
relationship: null
|
||||
relationship: null,
|
||||
});
|
||||
})
|
||||
.get("/profile/edit", async ctx => {
|
||||
.get("/profile/edit", async (ctx) => {
|
||||
const myFeedId = await meta.myFeedId();
|
||||
const description = await about.description(myFeedId);
|
||||
const name = await about.name(myFeedId);
|
||||
|
||||
ctx.body = await editProfileView({
|
||||
name,
|
||||
description
|
||||
description,
|
||||
});
|
||||
})
|
||||
.post("/profile/edit", koaBody({ multipart: true }), async ctx => {
|
||||
.post("/profile/edit", koaBody({ multipart: true }), async (ctx) => {
|
||||
const name = String(ctx.request.body.name);
|
||||
const description = String(ctx.request.body.description);
|
||||
|
||||
|
@ -365,14 +365,14 @@ router
|
|||
ctx.body = await post.publishProfileEdit({
|
||||
name,
|
||||
description,
|
||||
image
|
||||
image,
|
||||
});
|
||||
ctx.redirect("/profile");
|
||||
})
|
||||
.get("/publish/custom/", async ctx => {
|
||||
.get("/publish/custom/", async (ctx) => {
|
||||
ctx.body = await publishCustomView();
|
||||
})
|
||||
.get("/json/:message", async ctx => {
|
||||
.get("/json/:message", async (ctx) => {
|
||||
if (config.public) {
|
||||
throw new Error(
|
||||
"Sorry, many actions are unavailable when Oasis is running in public mode. Please run Oasis in the default mode and try again."
|
||||
|
@ -380,19 +380,19 @@ router
|
|||
}
|
||||
const { message } = ctx.params;
|
||||
ctx.type = "application/json";
|
||||
const json = async message => {
|
||||
const json = async (message) => {
|
||||
const json = await meta.get(message);
|
||||
return JSON.stringify(json, null, 2);
|
||||
};
|
||||
ctx.body = await json(message);
|
||||
})
|
||||
.get("/blob/:blobId", async ctx => {
|
||||
.get("/blob/:blobId", async (ctx) => {
|
||||
const { blobId } = ctx.params;
|
||||
const getBlob = async ({ blobId }) => {
|
||||
const bufferSource = await blob.get({ blobId });
|
||||
|
||||
debug("got buffer source");
|
||||
return new Promise(resolve => {
|
||||
return new Promise((resolve) => {
|
||||
pull(
|
||||
bufferSource,
|
||||
pull.collect(async (err, bufferArray) => {
|
||||
|
@ -428,7 +428,7 @@ router
|
|||
ctx.type = "image/svg+xml";
|
||||
}
|
||||
})
|
||||
.get("/image/:imageSize/:blobId", async ctx => {
|
||||
.get("/image/:imageSize/:blobId", async (ctx) => {
|
||||
const { blobId, imageSize } = ctx.params;
|
||||
if (sharp) {
|
||||
ctx.type = "image/png";
|
||||
|
@ -439,7 +439,7 @@ router
|
|||
"base64"
|
||||
);
|
||||
|
||||
const fakeImage = imageSize =>
|
||||
const fakeImage = (imageSize) =>
|
||||
sharp
|
||||
? sharp({
|
||||
create: {
|
||||
|
@ -450,23 +450,23 @@ router
|
|||
r: 0,
|
||||
g: 0,
|
||||
b: 0,
|
||||
alpha: 0.5
|
||||
}
|
||||
}
|
||||
alpha: 0.5,
|
||||
},
|
||||
},
|
||||
})
|
||||
.png()
|
||||
.toBuffer()
|
||||
: new Promise(resolve => resolve(fakePixel));
|
||||
: new Promise((resolve) => resolve(fakePixel));
|
||||
|
||||
const image = async ({ blobId, imageSize }) => {
|
||||
const bufferSource = await blob.get({ blobId });
|
||||
const fakeId = "&0000000000000000000000000000000000000000000=.sha256";
|
||||
|
||||
debug("got buffer source");
|
||||
return new Promise(resolve => {
|
||||
return new Promise((resolve) => {
|
||||
if (blobId === fakeId) {
|
||||
debug("fake image");
|
||||
fakeImage(imageSize).then(result => resolve(result));
|
||||
fakeImage(imageSize).then((result) => resolve(result));
|
||||
} else {
|
||||
debug("not fake image");
|
||||
pull(
|
||||
|
@ -485,7 +485,7 @@ router
|
|||
.resize(imageSize, imageSize)
|
||||
.png()
|
||||
.toBuffer()
|
||||
.then(data => {
|
||||
.then((data) => {
|
||||
resolve(data);
|
||||
});
|
||||
} else {
|
||||
|
@ -499,7 +499,7 @@ router
|
|||
};
|
||||
ctx.body = await image({ blobId, imageSize: Number(imageSize) });
|
||||
})
|
||||
.get("/settings/", async ctx => {
|
||||
.get("/settings/", async (ctx) => {
|
||||
const theme = ctx.cookies.get("theme") || defaultTheme;
|
||||
const getMeta = async ({ theme }) => {
|
||||
const status = await meta.status();
|
||||
|
@ -516,12 +516,12 @@ router
|
|||
peers: peersWithNames,
|
||||
theme,
|
||||
themeNames,
|
||||
version: config.version
|
||||
version: config.version,
|
||||
});
|
||||
};
|
||||
ctx.body = await getMeta({ theme });
|
||||
})
|
||||
.get("/likes/:feed", async ctx => {
|
||||
.get("/likes/:feed", async (ctx) => {
|
||||
const { feed } = ctx.params;
|
||||
const likes = async ({ feed }) => {
|
||||
const pendingMessages = post.likes({ feed });
|
||||
|
@ -529,18 +529,18 @@ router
|
|||
return likesView({
|
||||
messages: await pendingMessages,
|
||||
feed,
|
||||
name: await pendingName
|
||||
name: await pendingName,
|
||||
});
|
||||
};
|
||||
ctx.body = await likes({ feed });
|
||||
})
|
||||
.get("/settings/readme/", async ctx => {
|
||||
const status = async text => {
|
||||
.get("/settings/readme/", async (ctx) => {
|
||||
const status = async (text) => {
|
||||
return markdownView({ text });
|
||||
};
|
||||
ctx.body = await status(config.readme);
|
||||
})
|
||||
.get("/mentions/", async ctx => {
|
||||
.get("/mentions/", async (ctx) => {
|
||||
const mentions = async () => {
|
||||
const messages = await post.mentionsMe();
|
||||
|
||||
|
@ -548,9 +548,9 @@ router
|
|||
};
|
||||
ctx.body = await mentions();
|
||||
})
|
||||
.get("/thread/:message", async ctx => {
|
||||
.get("/thread/:message", async (ctx) => {
|
||||
const { message } = ctx.params;
|
||||
const thread = async message => {
|
||||
const thread = async (message) => {
|
||||
const messages = await post.fromThread(message);
|
||||
debug("got %i messages", messages.length);
|
||||
|
||||
|
@ -559,9 +559,9 @@ router
|
|||
|
||||
ctx.body = await thread(message);
|
||||
})
|
||||
.get("/reply/:message", async ctx => {
|
||||
.get("/reply/:message", async (ctx) => {
|
||||
const { message } = ctx.params;
|
||||
const reply = async parentId => {
|
||||
const reply = async (parentId) => {
|
||||
const rootMessage = await post.get(parentId);
|
||||
const myFeedId = await meta.myFeedId();
|
||||
|
||||
|
@ -572,12 +572,12 @@ router
|
|||
};
|
||||
ctx.body = await reply(message);
|
||||
})
|
||||
.get("/publish", async ctx => {
|
||||
.get("/publish", async (ctx) => {
|
||||
ctx.body = await publishView();
|
||||
})
|
||||
.get("/comment/:message", async ctx => {
|
||||
.get("/comment/:message", async (ctx) => {
|
||||
const { message } = ctx.params;
|
||||
const comment = async parentId => {
|
||||
const comment = async (parentId) => {
|
||||
const parentMessage = await post.get(parentId);
|
||||
const myFeedId = await meta.myFeedId();
|
||||
|
||||
|
@ -602,7 +602,7 @@ router
|
|||
};
|
||||
ctx.body = await comment(message);
|
||||
})
|
||||
.post("/reply/:message", koaBody(), async ctx => {
|
||||
.post("/reply/:message", koaBody(), async (ctx) => {
|
||||
const { message } = ctx.params;
|
||||
const text = String(ctx.request.body.text);
|
||||
const publishReply = async ({ message, text }) => {
|
||||
|
@ -612,13 +612,13 @@ router
|
|||
const parent = await post.get(message);
|
||||
return post.reply({
|
||||
parent,
|
||||
message: { text, mentions }
|
||||
message: { text, mentions },
|
||||
});
|
||||
};
|
||||
ctx.body = await publishReply({ message, text });
|
||||
ctx.redirect(`/thread/${encodeURIComponent(message)}`);
|
||||
})
|
||||
.post("/comment/:message", koaBody(), async ctx => {
|
||||
.post("/comment/:message", koaBody(), async (ctx) => {
|
||||
const { message } = ctx.params;
|
||||
const text = String(ctx.request.body.text);
|
||||
const publishComment = async ({ message, text }) => {
|
||||
|
@ -628,13 +628,13 @@ router
|
|||
|
||||
return post.comment({
|
||||
parent,
|
||||
message: { text, mentions }
|
||||
message: { text, mentions },
|
||||
});
|
||||
};
|
||||
ctx.body = await publishComment({ message, text });
|
||||
ctx.redirect(`/thread/${encodeURIComponent(message)}`);
|
||||
})
|
||||
.post("/publish/", koaBody(), async ctx => {
|
||||
.post("/publish/", koaBody(), async (ctx) => {
|
||||
const text = String(ctx.request.body.text);
|
||||
const rawContentWarning = String(ctx.request.body.contentWarning);
|
||||
|
||||
|
@ -648,31 +648,31 @@ router
|
|||
return post.root({
|
||||
text,
|
||||
mentions,
|
||||
contentWarning
|
||||
contentWarning,
|
||||
});
|
||||
};
|
||||
ctx.body = await publish({ text, contentWarning });
|
||||
ctx.redirect("/public/latest");
|
||||
})
|
||||
.post("/publish/custom", koaBody(), async ctx => {
|
||||
.post("/publish/custom", koaBody(), async (ctx) => {
|
||||
const text = String(ctx.request.body.text);
|
||||
const obj = JSON.parse(text);
|
||||
ctx.body = await post.publishCustom(obj);
|
||||
ctx.redirect(`/public/latest`);
|
||||
})
|
||||
.post("/follow/:feed", koaBody(), async ctx => {
|
||||
.post("/follow/:feed", koaBody(), async (ctx) => {
|
||||
const { feed } = ctx.params;
|
||||
const referer = new URL(ctx.request.header.referer);
|
||||
ctx.body = await friend.follow(feed);
|
||||
ctx.redirect(referer);
|
||||
})
|
||||
.post("/unfollow/:feed", koaBody(), async ctx => {
|
||||
.post("/unfollow/:feed", koaBody(), async (ctx) => {
|
||||
const { feed } = ctx.params;
|
||||
const referer = new URL(ctx.request.header.referer);
|
||||
ctx.body = await friend.unfollow(feed);
|
||||
ctx.redirect(referer);
|
||||
})
|
||||
.post("/like/:message", koaBody(), async ctx => {
|
||||
.post("/like/:message", koaBody(), async (ctx) => {
|
||||
const { message } = ctx.params;
|
||||
// TODO: convert all so `message` is full message and `messageKey` is key
|
||||
const messageKey = message;
|
||||
|
@ -680,7 +680,7 @@ router
|
|||
const voteValue = Number(ctx.request.body.voteValue);
|
||||
|
||||
const encoded = {
|
||||
message: encodeURIComponent(message)
|
||||
message: encodeURIComponent(message),
|
||||
};
|
||||
|
||||
const referer = new URL(ctx.request.header.referer);
|
||||
|
@ -693,7 +693,7 @@ router
|
|||
const isPrivate = message.value.meta.private === true;
|
||||
const messageRecipients = isPrivate ? message.value.content.recps : [];
|
||||
|
||||
const normalized = messageRecipients.map(recipient => {
|
||||
const normalized = messageRecipients.map((recipient) => {
|
||||
if (typeof recipient === "string") {
|
||||
return recipient;
|
||||
}
|
||||
|
@ -712,31 +712,31 @@ router
|
|||
ctx.body = await like({ messageKey, voteValue });
|
||||
ctx.redirect(referer);
|
||||
})
|
||||
.post("/theme.css", koaBody(), async ctx => {
|
||||
.post("/theme.css", koaBody(), async (ctx) => {
|
||||
const theme = String(ctx.request.body.theme);
|
||||
ctx.cookies.set("theme", theme);
|
||||
const referer = new URL(ctx.request.header.referer);
|
||||
ctx.redirect(referer);
|
||||
})
|
||||
.post("/language", koaBody(), async ctx => {
|
||||
.post("/language", koaBody(), async (ctx) => {
|
||||
const language = String(ctx.request.body.language);
|
||||
ctx.cookies.set("language", language);
|
||||
const referer = new URL(ctx.request.header.referer);
|
||||
ctx.redirect(referer);
|
||||
})
|
||||
.post("/settings/conn/start", koaBody(), async ctx => {
|
||||
.post("/settings/conn/start", koaBody(), async (ctx) => {
|
||||
await meta.connStart();
|
||||
ctx.redirect("/settings");
|
||||
})
|
||||
.post("/settings/conn/stop", koaBody(), async ctx => {
|
||||
.post("/settings/conn/stop", koaBody(), async (ctx) => {
|
||||
await meta.connStop();
|
||||
ctx.redirect("/settings");
|
||||
})
|
||||
.post("/settings/conn/restart", koaBody(), async ctx => {
|
||||
.post("/settings/conn/restart", koaBody(), async (ctx) => {
|
||||
await meta.connRestart();
|
||||
ctx.redirect("/settings");
|
||||
})
|
||||
.post("/settings/invite/accept", koaBody(), async ctx => {
|
||||
.post("/settings/invite/accept", koaBody(), async (ctx) => {
|
||||
const invite = String(ctx.request.body.invite);
|
||||
await meta.acceptInvite(invite);
|
||||
ctx.redirect("/settings");
|
||||
|
@ -781,7 +781,7 @@ const middleware = [
|
|||
await next();
|
||||
}
|
||||
},
|
||||
routes
|
||||
routes,
|
||||
];
|
||||
|
||||
http({ host, port, middleware });
|
||||
|
|
281
src/models.js
281
src/models.js
|
@ -18,11 +18,11 @@ const nullImage = `&${"0".repeat(43)}=.sha256`;
|
|||
const defaultOptions = {
|
||||
private: true,
|
||||
reverse: true,
|
||||
meta: true
|
||||
meta: true,
|
||||
};
|
||||
|
||||
const publicOnlyFilter = pull.filter(
|
||||
message => lodash.get(message, "value.meta.private", false) === false
|
||||
(message) => lodash.get(message, "value.meta.private", false) === false
|
||||
);
|
||||
|
||||
/** @param {object[]} customOptions */
|
||||
|
@ -55,16 +55,19 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
{
|
||||
$filter: {
|
||||
dest: feedId,
|
||||
value: { author: feedId, content: { type: "about", about: feedId } }
|
||||
}
|
||||
}
|
||||
]
|
||||
value: {
|
||||
author: feedId,
|
||||
content: { type: "about", about: feedId },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
return new Promise((resolve, reject) =>
|
||||
pull(
|
||||
source,
|
||||
pull.find(
|
||||
message => message.value.content[key] !== undefined,
|
||||
(message) => message.value.content[key] !== undefined,
|
||||
(err, message) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
|
@ -82,14 +85,14 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
};
|
||||
|
||||
models.about = {
|
||||
publicWebHosting: async feedId => {
|
||||
publicWebHosting: async (feedId) => {
|
||||
const result = await getAbout({
|
||||
key: "publicWebHosting",
|
||||
feedId
|
||||
feedId,
|
||||
});
|
||||
return result === true;
|
||||
},
|
||||
name: async feedId => {
|
||||
name: async (feedId) => {
|
||||
if (isPublic && (await models.about.publicWebHosting(feedId)) === false) {
|
||||
return "Redacted";
|
||||
}
|
||||
|
@ -97,18 +100,18 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
return (
|
||||
(await getAbout({
|
||||
key: "name",
|
||||
feedId
|
||||
feedId,
|
||||
})) || feedId.slice(1, 1 + 8)
|
||||
); // First 8 chars of public key
|
||||
},
|
||||
image: async feedId => {
|
||||
image: async (feedId) => {
|
||||
if (isPublic && (await models.about.publicWebHosting(feedId)) === false) {
|
||||
return nullImage;
|
||||
}
|
||||
|
||||
const raw = await getAbout({
|
||||
key: "image",
|
||||
feedId
|
||||
feedId,
|
||||
});
|
||||
|
||||
if (raw == null || raw.link == null) {
|
||||
|
@ -120,7 +123,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
}
|
||||
return raw;
|
||||
},
|
||||
description: async feedId => {
|
||||
description: async (feedId) => {
|
||||
if (isPublic && (await models.about.publicWebHosting(feedId)) === false) {
|
||||
return "Redacted";
|
||||
}
|
||||
|
@ -128,10 +131,10 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const raw =
|
||||
(await getAbout({
|
||||
key: "description",
|
||||
feedId
|
||||
feedId,
|
||||
})) || "";
|
||||
return raw;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
models.blob = {
|
||||
|
@ -146,17 +149,17 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
|
||||
// This does not wait for the blob.
|
||||
ssb.blobs.want(blobId);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
models.friend = {
|
||||
isFollowing: async feedId => {
|
||||
isFollowing: async (feedId) => {
|
||||
const ssb = await cooler.open();
|
||||
const { id } = ssb;
|
||||
|
||||
const isFollowing = await ssb.friends.isFollowing({
|
||||
source: id,
|
||||
dest: feedId
|
||||
dest: feedId,
|
||||
});
|
||||
return isFollowing;
|
||||
},
|
||||
|
@ -166,24 +169,24 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const content = {
|
||||
type: "contact",
|
||||
contact: feedId,
|
||||
following
|
||||
following,
|
||||
};
|
||||
|
||||
return ssb.publish(content);
|
||||
},
|
||||
follow: async feedId => {
|
||||
follow: async (feedId) => {
|
||||
const isFollowing = await models.friend.isFollowing(feedId);
|
||||
if (!isFollowing) {
|
||||
await models.friend.setFollowing({ feedId, following: true });
|
||||
}
|
||||
},
|
||||
unfollow: async feedId => {
|
||||
unfollow: async (feedId) => {
|
||||
const isFollowing = await models.friend.isFollowing(feedId);
|
||||
if (isFollowing) {
|
||||
await models.friend.setFollowing({ feedId, following: false });
|
||||
}
|
||||
},
|
||||
getRelationship: async feedId => {
|
||||
getRelationship: async (feedId) => {
|
||||
const ssb = await cooler.open();
|
||||
const { id } = ssb;
|
||||
|
||||
|
@ -193,19 +196,19 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
|
||||
const isFollowing = await ssb.friends.isFollowing({
|
||||
source: id,
|
||||
dest: feedId
|
||||
dest: feedId,
|
||||
});
|
||||
|
||||
const isBlocking = await ssb.friends.isBlocking({
|
||||
source: id,
|
||||
dest: feedId
|
||||
dest: feedId,
|
||||
});
|
||||
|
||||
return {
|
||||
following: isFollowing,
|
||||
blocking: isBlocking
|
||||
blocking: isBlocking,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
models.meta = {
|
||||
|
@ -214,12 +217,12 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const { id } = ssb;
|
||||
return id;
|
||||
},
|
||||
get: async msgId => {
|
||||
get: async (msgId) => {
|
||||
const ssb = await cooler.open();
|
||||
return ssb.get({
|
||||
id: msgId,
|
||||
meta: true,
|
||||
private: true
|
||||
private: true,
|
||||
});
|
||||
},
|
||||
status: async () => {
|
||||
|
@ -269,44 +272,44 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
await models.meta.connStop();
|
||||
await models.meta.connStart();
|
||||
},
|
||||
acceptInvite: async invite => {
|
||||
acceptInvite: async (invite) => {
|
||||
const ssb = await cooler.open();
|
||||
return await ssb.invite.accept(invite);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const isPost = message =>
|
||||
const isPost = (message) =>
|
||||
lodash.get(message, "value.content.type") === "post" &&
|
||||
lodash.get(message, "value.content.text") != null;
|
||||
|
||||
const isLooseRoot = message => {
|
||||
const isLooseRoot = (message) => {
|
||||
const conditions = [
|
||||
isPost(message),
|
||||
lodash.get(message, "value.content.root") == null,
|
||||
lodash.get(message, "value.content.fork") == null
|
||||
lodash.get(message, "value.content.fork") == null,
|
||||
];
|
||||
|
||||
return conditions.every(x => x);
|
||||
return conditions.every((x) => x);
|
||||
};
|
||||
|
||||
const isLooseReply = message => {
|
||||
const isLooseReply = (message) => {
|
||||
const conditions = [
|
||||
isPost(message),
|
||||
lodash.get(message, "value.content.root") != null,
|
||||
lodash.get(message, "value.content.fork") != null
|
||||
lodash.get(message, "value.content.fork") != null,
|
||||
];
|
||||
|
||||
return conditions.every(x => x);
|
||||
return conditions.every((x) => x);
|
||||
};
|
||||
|
||||
const isLooseComment = message => {
|
||||
const isLooseComment = (message) => {
|
||||
const conditions = [
|
||||
isPost(message),
|
||||
lodash.get(message, "value.content.root") != null,
|
||||
lodash.get(message, "value.content.fork") == null
|
||||
lodash.get(message, "value.content.fork") == null,
|
||||
];
|
||||
|
||||
return conditions.every(x => x === true);
|
||||
return conditions.every((x) => x === true);
|
||||
};
|
||||
|
||||
const maxMessages = 64;
|
||||
|
@ -316,7 +319,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
customOptions,
|
||||
ssb,
|
||||
query,
|
||||
filter = null
|
||||
filter = null,
|
||||
}) => {
|
||||
const options = configure({ query, index: "DTA" }, customOptions);
|
||||
|
||||
|
@ -328,7 +331,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
source,
|
||||
basicSocialFilter,
|
||||
pull.filter(
|
||||
msg =>
|
||||
(msg) =>
|
||||
typeof msg.value.content !== "string" &&
|
||||
msg.value.content.type === "post" &&
|
||||
(filter == null || filter(msg) === true)
|
||||
|
@ -356,12 +359,12 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const socialFilter = async ({
|
||||
following = null,
|
||||
blocking = false,
|
||||
me = null
|
||||
me = null,
|
||||
} = {}) => {
|
||||
const ssb = await cooler.open();
|
||||
const { id } = ssb;
|
||||
const relationshipObject = await ssb.friends.get({
|
||||
source: id
|
||||
source: id,
|
||||
});
|
||||
|
||||
const followingList = Object.entries(relationshipObject)
|
||||
|
@ -372,7 +375,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
.filter(([, val]) => val === false)
|
||||
.map(([key]) => key);
|
||||
|
||||
return pull.filter(message => {
|
||||
return pull.filter((message) => {
|
||||
if (message.value.author === id) {
|
||||
return me !== false;
|
||||
} else {
|
||||
|
@ -387,7 +390,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
};
|
||||
const transform = (ssb, messages, myFeedId) =>
|
||||
Promise.all(
|
||||
messages.map(async msg => {
|
||||
messages.map(async (msg) => {
|
||||
debug("transforming %s", msg.key);
|
||||
|
||||
if (msg == null) {
|
||||
|
@ -396,22 +399,22 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
|
||||
const filterQuery = {
|
||||
$filter: {
|
||||
dest: msg.key
|
||||
}
|
||||
dest: msg.key,
|
||||
},
|
||||
};
|
||||
|
||||
const referenceStream = ssb.backlinks.read({
|
||||
query: [filterQuery],
|
||||
index: "DTA", // use asserted timestamps
|
||||
private: true,
|
||||
meta: true
|
||||
meta: true,
|
||||
});
|
||||
|
||||
const rawVotes = await new Promise((resolve, reject) => {
|
||||
pull(
|
||||
referenceStream,
|
||||
pull.filter(
|
||||
ref =>
|
||||
(ref) =>
|
||||
typeof ref.value.content !== "string" &&
|
||||
ref.value.content.type === "vote" &&
|
||||
ref.value.content.vote &&
|
||||
|
@ -500,7 +503,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
lodash.set(msg, "value.meta.author.name", name);
|
||||
lodash.set(msg, "value.meta.author.avatar", {
|
||||
id: avatarId,
|
||||
url: avatarUrl
|
||||
url: avatarUrl,
|
||||
});
|
||||
|
||||
const isPost =
|
||||
|
@ -539,7 +542,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
pull(
|
||||
source,
|
||||
pull.filter(
|
||||
msg =>
|
||||
(msg) =>
|
||||
lodash.get(msg, "value.meta.private", false) === false &&
|
||||
msg.value.content.type === "post"
|
||||
),
|
||||
|
@ -564,9 +567,9 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const query = [
|
||||
{
|
||||
$filter: {
|
||||
dest: myFeedId
|
||||
}
|
||||
}
|
||||
dest: myFeedId,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const messages = await getMessages({
|
||||
|
@ -574,9 +577,9 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
customOptions,
|
||||
ssb,
|
||||
query,
|
||||
filter: msg =>
|
||||
filter: (msg) =>
|
||||
msg.value.author !== myFeedId &&
|
||||
lodash.get(msg, "value.meta.private") !== true
|
||||
lodash.get(msg, "value.meta.private") !== true,
|
||||
});
|
||||
|
||||
return messages;
|
||||
|
@ -589,16 +592,16 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const query = [
|
||||
{
|
||||
$filter: {
|
||||
dest: `#${hashtag}`
|
||||
}
|
||||
}
|
||||
dest: `#${hashtag}`,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const messages = await getMessages({
|
||||
myFeedId,
|
||||
customOptions,
|
||||
ssb,
|
||||
query
|
||||
query,
|
||||
});
|
||||
|
||||
return messages;
|
||||
|
@ -611,9 +614,9 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const query = [
|
||||
{
|
||||
$filter: {
|
||||
dest: rootId
|
||||
}
|
||||
}
|
||||
dest: rootId,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const messages = await getMessages({
|
||||
|
@ -621,8 +624,8 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
customOptions,
|
||||
ssb,
|
||||
query,
|
||||
filter: msg =>
|
||||
msg.value.content.root === rootId && msg.value.content.fork == null
|
||||
filter: (msg) =>
|
||||
msg.value.content.root === rootId && msg.value.content.fork == null,
|
||||
});
|
||||
|
||||
return messages;
|
||||
|
@ -637,17 +640,17 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
author: feed,
|
||||
timestamp: { $lte: Date.now() },
|
||||
content: {
|
||||
type: "vote"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
type: "vote",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const options = configure(
|
||||
{
|
||||
query,
|
||||
reverse: true
|
||||
reverse: true,
|
||||
},
|
||||
customOptions
|
||||
);
|
||||
|
@ -657,7 +660,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const messages = await new Promise((resolve, reject) => {
|
||||
pull(
|
||||
source,
|
||||
pull.filter(msg => {
|
||||
pull.filter((msg) => {
|
||||
return (
|
||||
typeof msg.value.content === "object" &&
|
||||
msg.value.author === feed &&
|
||||
|
@ -688,7 +691,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const myFeedId = ssb.id;
|
||||
|
||||
const options = configure({
|
||||
query
|
||||
query,
|
||||
});
|
||||
|
||||
const source = await ssb.search.query(options);
|
||||
|
@ -729,12 +732,12 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
value: {
|
||||
timestamp: { $lte: Date.now() },
|
||||
content: {
|
||||
type: "post"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
type: "post",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
const followingFilter = await socialFilter({ following: true });
|
||||
|
@ -770,18 +773,18 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
value: {
|
||||
timestamp: { $lte: Date.now() },
|
||||
content: {
|
||||
type: "post"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
type: "post",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
const extendedFilter = await socialFilter({
|
||||
following: false,
|
||||
me: false
|
||||
me: false,
|
||||
});
|
||||
|
||||
const messages = await new Promise((resolve, reject) => {
|
||||
|
@ -815,24 +818,24 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
value: {
|
||||
timestamp: { $lte: Date.now() },
|
||||
content: {
|
||||
type: "post"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
type: "post",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
const extendedFilter = await socialFilter({
|
||||
following: true
|
||||
following: true,
|
||||
});
|
||||
|
||||
const messages = await new Promise((resolve, reject) => {
|
||||
pull(
|
||||
source,
|
||||
publicOnlyFilter,
|
||||
pull.filter(message => message.value.content.root == null),
|
||||
pull.filter((message) => message.value.content.root == null),
|
||||
extendedFilter,
|
||||
pull.take(maxMessages),
|
||||
pull.collect((err, collectedMessages) => {
|
||||
|
@ -854,20 +857,20 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
|
||||
const options = configure({
|
||||
type: "post",
|
||||
private: false
|
||||
private: false,
|
||||
});
|
||||
|
||||
const source = ssb.messagesByType(options);
|
||||
|
||||
const extendedFilter = await socialFilter({
|
||||
following: true
|
||||
following: true,
|
||||
});
|
||||
|
||||
const messages = await new Promise((resolve, reject) => {
|
||||
pull(
|
||||
source,
|
||||
pull.filter(
|
||||
message =>
|
||||
(message) =>
|
||||
typeof message.value.content !== "string" &&
|
||||
message.value.content.root == null
|
||||
),
|
||||
|
@ -903,7 +906,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
day: 1,
|
||||
week: 7,
|
||||
month: 30.42,
|
||||
year: 365
|
||||
year: 365,
|
||||
};
|
||||
|
||||
if (period in periodDict === false) {
|
||||
|
@ -923,12 +926,12 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
value: {
|
||||
timestamp: { $gte: earliest },
|
||||
content: {
|
||||
type: "vote"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
type: "vote",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
const basicSocialFilter = await socialFilter();
|
||||
|
@ -937,7 +940,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
pull(
|
||||
source,
|
||||
publicOnlyFilter,
|
||||
pull.filter(msg => {
|
||||
pull.filter((msg) => {
|
||||
return (
|
||||
typeof msg.value.content === "object" &&
|
||||
typeof msg.value.content.vote === "object" &&
|
||||
|
@ -1008,7 +1011,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
}),
|
||||
// avoid private messages (!) and non-posts
|
||||
pull.filter(
|
||||
message =>
|
||||
(message) =>
|
||||
message &&
|
||||
typeof message.value.content !== "string" &&
|
||||
message.value.content.type === "post"
|
||||
|
@ -1038,12 +1041,12 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const options = configure({ id: msgId }, customOptions);
|
||||
return ssb
|
||||
.get(options)
|
||||
.then(async rawMsg => {
|
||||
.then(async (rawMsg) => {
|
||||
debug("got raw message");
|
||||
|
||||
const parents = [];
|
||||
|
||||
const getRootAncestor = msg =>
|
||||
const getRootAncestor = (msg) =>
|
||||
new Promise((resolve, reject) => {
|
||||
if (msg.key == null) {
|
||||
debug("something is very wrong, we used `{ meta: true }`");
|
||||
|
@ -1070,9 +1073,9 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
.get({
|
||||
id: msg.value.content.fork,
|
||||
meta: true,
|
||||
private: true
|
||||
private: true,
|
||||
})
|
||||
.then(fork => {
|
||||
.then((fork) => {
|
||||
resolve(getRootAncestor(fork));
|
||||
})
|
||||
.catch(reject);
|
||||
|
@ -1091,9 +1094,9 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
.get({
|
||||
id: msg.value.content.root,
|
||||
meta: true,
|
||||
private: true
|
||||
private: true,
|
||||
})
|
||||
.then(root => {
|
||||
.then((root) => {
|
||||
resolve(getRootAncestor(root));
|
||||
})
|
||||
.catch(reject);
|
||||
|
@ -1116,21 +1119,21 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
}
|
||||
});
|
||||
|
||||
const getReplies = key =>
|
||||
const getReplies = (key) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const filterQuery = {
|
||||
$filter: {
|
||||
dest: key
|
||||
}
|
||||
dest: key,
|
||||
},
|
||||
};
|
||||
|
||||
const referenceStream = ssb.backlinks.read({
|
||||
query: [filterQuery],
|
||||
index: "DTA" // use asserted timestamps
|
||||
index: "DTA", // use asserted timestamps
|
||||
});
|
||||
pull(
|
||||
referenceStream,
|
||||
pull.filter(msg => {
|
||||
pull.filter((msg) => {
|
||||
const isPost =
|
||||
lodash.get(msg, "value.content.type") === "post";
|
||||
if (isPost === false) {
|
||||
|
@ -1164,7 +1167,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
});
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
|
||||
const flattenDeep = arr1 =>
|
||||
const flattenDeep = (arr1) =>
|
||||
arr1.reduce(
|
||||
(acc, val) =>
|
||||
Array.isArray(val)
|
||||
|
@ -1173,13 +1176,13 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
[]
|
||||
);
|
||||
|
||||
const getDeepReplies = key =>
|
||||
const getDeepReplies = (key) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const oneDeeper = async (replyKey, depth) => {
|
||||
const replies = await getReplies(replyKey);
|
||||
debug(
|
||||
"replies",
|
||||
replies.map(m => m.key)
|
||||
replies.map((m) => m.key)
|
||||
);
|
||||
|
||||
debug("found %s replies for %s", replies.length, replyKey);
|
||||
|
@ -1188,7 +1191,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
return replies;
|
||||
}
|
||||
return Promise.all(
|
||||
replies.map(async reply => {
|
||||
replies.map(async (reply) => {
|
||||
const deeperReplies = await oneDeeper(reply.key, depth + 1);
|
||||
lodash.set(reply, "value.meta.thread.depth", depth);
|
||||
lodash.set(reply, "value.meta.thread.reply", true);
|
||||
|
@ -1197,7 +1200,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
);
|
||||
};
|
||||
oneDeeper(key, 0)
|
||||
.then(nested => {
|
||||
.then((nested) => {
|
||||
const nestedReplies = [...nested];
|
||||
const deepReplies = flattenDeep(nestedReplies);
|
||||
resolve(deepReplies);
|
||||
|
@ -1211,7 +1214,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
const deepReplies = await getDeepReplies(rootAncestor.key);
|
||||
debug("got deep replies");
|
||||
|
||||
const allMessages = [rootAncestor, ...deepReplies].map(message => {
|
||||
const allMessages = [rootAncestor, ...deepReplies].map((message) => {
|
||||
const isThreadTarget = message.key === msgId;
|
||||
lodash.set(message, "value.meta.thread.target", isThreadTarget);
|
||||
return message;
|
||||
|
@ -1219,7 +1222,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
|
||||
return await transform(ssb, allMessages, myFeedId);
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
if (err.name === "NotFoundError") {
|
||||
throw new Error(
|
||||
"Message not found in the database. You've done nothing wrong. Maybe try again later?"
|
||||
|
@ -1243,7 +1246,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
debug("transformed: %O", transformed);
|
||||
return transformed[0];
|
||||
},
|
||||
publish: async options => {
|
||||
publish: async (options) => {
|
||||
const ssb = await cooler.open();
|
||||
const body = { type: "post", ...options };
|
||||
|
||||
|
@ -1269,7 +1272,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
return new Promise((resolve, reject) => {
|
||||
pull(
|
||||
pull.values([image]),
|
||||
ssb.blobs.add(blobId, err => {
|
||||
ssb.blobs.add(blobId, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
|
@ -1278,7 +1281,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
about: ssb.id,
|
||||
name,
|
||||
description,
|
||||
image: blobId
|
||||
image: blobId,
|
||||
};
|
||||
debug("Published: %O", body);
|
||||
resolve(ssb.publish(body));
|
||||
|
@ -1292,7 +1295,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
return ssb.publish(body);
|
||||
}
|
||||
},
|
||||
publishCustom: async options => {
|
||||
publishCustom: async (options) => {
|
||||
const ssb = await cooler.open();
|
||||
debug("Published: %O", options);
|
||||
return ssb.publish(options);
|
||||
|
@ -1310,7 +1313,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
|
||||
return post.publish(message);
|
||||
},
|
||||
root: async options => {
|
||||
root: async (options) => {
|
||||
const message = { type: "post", ...options };
|
||||
|
||||
if (isRoot(message) !== true) {
|
||||
|
@ -1333,7 +1336,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
if (isPrivate) {
|
||||
message.recps = lodash
|
||||
.get(parent, "value.content.recps", [])
|
||||
.map(recipient => {
|
||||
.map((recipient) => {
|
||||
if (
|
||||
typeof recipient === "object" &&
|
||||
typeof recipient.link === "string" &&
|
||||
|
@ -1379,7 +1382,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
|
||||
const options = configure(
|
||||
{
|
||||
query: [{ $filter: { dest: ssb.id } }]
|
||||
query: [{ $filter: { dest: ssb.id } }],
|
||||
},
|
||||
customOptions
|
||||
);
|
||||
|
@ -1391,12 +1394,12 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
source,
|
||||
// Make sure we're only getting private messages that are posts.
|
||||
pull.filter(
|
||||
message =>
|
||||
(message) =>
|
||||
typeof message.value.content !== "string" &&
|
||||
lodash.get(message, "value.meta.private") &&
|
||||
lodash.get(message, "value.content.type") === "post"
|
||||
),
|
||||
pull.unique(message => {
|
||||
pull.unique((message) => {
|
||||
const { root } = message.value.content;
|
||||
if (root == null) {
|
||||
return message.key;
|
||||
|
@ -1416,7 +1419,7 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
});
|
||||
|
||||
return messages;
|
||||
}
|
||||
},
|
||||
};
|
||||
models.post = post;
|
||||
|
||||
|
@ -1430,12 +1433,12 @@ module.exports = ({ cooler, isPublic }) => {
|
|||
type: "vote",
|
||||
vote: {
|
||||
link: messageKey,
|
||||
value: Number(value)
|
||||
value: Number(value),
|
||||
},
|
||||
branch,
|
||||
recps
|
||||
recps,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return models;
|
||||
|
|
26
src/ssb.js
26
src/ssb.js
|
@ -18,7 +18,7 @@ const remote = `unix:${socketPath}~noauth:${publicInteger}`;
|
|||
|
||||
// This is unnecessary when https://github.com/ssbc/ssb-config/pull/72 is merged
|
||||
ssbConfig.connections.incoming.unix = [
|
||||
{ scope: "device", transform: "noauth" }
|
||||
{ scope: "device", transform: "noauth" },
|
||||
];
|
||||
|
||||
const server = flotilla(ssbConfig);
|
||||
|
@ -33,7 +33,7 @@ const log = (...args) => {
|
|||
const rawConnect = () =>
|
||||
new Promise((resolve, reject) => {
|
||||
ssbClient(null, { remote })
|
||||
.then(api => {
|
||||
.then((api) => {
|
||||
if (api.tangle === undefined) {
|
||||
// HACK: SSB-Tangle isn't available in Patchwork, but we want that
|
||||
// compatibility. This code automatically injects SSB-Tangle into our
|
||||
|
@ -53,14 +53,14 @@ const rawConnect = () =>
|
|||
|
||||
let handle;
|
||||
|
||||
const createConnection = config => {
|
||||
handle = new Promise(resolve => {
|
||||
const createConnection = (config) => {
|
||||
handle = new Promise((resolve) => {
|
||||
rawConnect()
|
||||
.then(ssb => {
|
||||
.then((ssb) => {
|
||||
log("Using pre-existing Scuttlebutt server instead of starting one");
|
||||
resolve(ssb);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch((e) => {
|
||||
if (e.message !== "could not connect to sbot") {
|
||||
throw e;
|
||||
}
|
||||
|
@ -69,11 +69,11 @@ const createConnection = config => {
|
|||
server(config);
|
||||
const connectOrRetry = () => {
|
||||
rawConnect()
|
||||
.then(ssb => {
|
||||
.then((ssb) => {
|
||||
log("Retrying connection to own server");
|
||||
resolve(ssb);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch((e) => {
|
||||
if (e.message !== "could not connect to sbot") {
|
||||
log(e);
|
||||
}
|
||||
|
@ -98,8 +98,8 @@ module.exports = ({ offline }) => {
|
|||
|
||||
const config = {
|
||||
conn: {
|
||||
autostart: !offline
|
||||
}
|
||||
autostart: !offline,
|
||||
},
|
||||
};
|
||||
|
||||
createConnection(config);
|
||||
|
@ -117,14 +117,14 @@ module.exports = ({ offline }) => {
|
|||
// If the connection is closed, we need to restart it. It's important to
|
||||
// note that if we're depending on an external service (like Patchwork) and
|
||||
// that app is closed, then Oasis will seamlessly start its own SSB service.
|
||||
return new Promise(resolve => {
|
||||
handle.then(ssb => {
|
||||
return new Promise((resolve) => {
|
||||
handle.then((ssb) => {
|
||||
if (ssb.closed) {
|
||||
createConnection();
|
||||
}
|
||||
resolve(handle);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ module.exports = {
|
|||
extendedDescription: [
|
||||
"Posts from ",
|
||||
strong("people you don't follow"),
|
||||
", sorted by recency. When you follow someone you may download messages from the people they follow, and those messages show up here."
|
||||
", sorted by recency. When you follow someone you may download messages from the people they follow, and those messages show up here.",
|
||||
],
|
||||
popular: "Popular",
|
||||
popularDescription: [
|
||||
|
@ -15,7 +15,7 @@ module.exports = {
|
|||
strong("hearts"),
|
||||
" in a given period. Hearts are counted from ",
|
||||
em("everyone"),
|
||||
", including people you don't follow, so this shows posts from your friends that are popular in your extended network."
|
||||
", including people you don't follow, so this shows posts from your friends that are popular in your extended network.",
|
||||
],
|
||||
latest: "Latest",
|
||||
latestDescription:
|
||||
|
@ -23,12 +23,12 @@ module.exports = {
|
|||
topics: "Topics",
|
||||
topicsDescription: [
|
||||
strong("Topics"),
|
||||
" from yourself and people you follow, sorted by recency. Select the timestamp of any post to see the rest of the thread."
|
||||
" from yourself and people you follow, sorted by recency. Select the timestamp of any post to see the rest of the thread.",
|
||||
],
|
||||
summaries: "Summaries",
|
||||
summariesDescription: [
|
||||
strong("Topics and some comments"),
|
||||
" from yourself and people you follow, sorted by recency. Select the timestamp of any post to see the rest of the thread."
|
||||
" from yourself and people you follow, sorted by recency. Select the timestamp of any post to see the rest of the thread.",
|
||||
],
|
||||
profile: "Profile",
|
||||
manualMode: "Manual Mode",
|
||||
|
@ -37,13 +37,13 @@ module.exports = {
|
|||
strong("Posts that mention you"),
|
||||
" from ",
|
||||
strong("anyone"),
|
||||
" sorted by recency. Sometimes people may forget to @mention you, and those posts won't show up here."
|
||||
" sorted by recency. Sometimes people may forget to @mention you, and those posts won't show up here.",
|
||||
],
|
||||
private: "Private",
|
||||
privateDescription: [
|
||||
"The latest comment from ",
|
||||
strong("private threads that include you"),
|
||||
", sorted by recency. Private posts are encrypted for your public key, and have a maximum of 7 recipients. Recipients cannot be added after the thread has started. Select the timestamp to view the full thread."
|
||||
", sorted by recency. Private posts are encrypted for your public key, and have a maximum of 7 recipients. Recipients cannot be added after the thread has started. Select the timestamp to view the full thread.",
|
||||
],
|
||||
search: "Search",
|
||||
settings: "Settings",
|
||||
|
@ -69,12 +69,12 @@ module.exports = {
|
|||
publishCustomDescription: [
|
||||
"Publish a custom message by entering ",
|
||||
a({ href: "https://en.wikipedia.org/wiki/JSON" }, "JSON"),
|
||||
" below. This may be useful for prototyping or publishing messages that Oasis doesn't support. This message cannot be edited or deleted."
|
||||
" below. This may be useful for prototyping or publishing messages that Oasis doesn't support. This message cannot be edited or deleted.",
|
||||
],
|
||||
commentWarning: [
|
||||
" Comments cannot be edited or deleted. To respond to an individual message, select ",
|
||||
strong("reply"),
|
||||
" instead."
|
||||
" instead.",
|
||||
],
|
||||
commentPublic: "public",
|
||||
commentPrivate: "private",
|
||||
|
@ -83,28 +83,28 @@ module.exports = {
|
|||
strong(`${publicOrPrivate} comment`),
|
||||
" on this thread with ",
|
||||
a({ href: markdownUrl }, "Markdown"),
|
||||
"."
|
||||
".",
|
||||
],
|
||||
publishLabel: ({ markdownUrl, linkTarget }) => [
|
||||
"Write a new public post in ",
|
||||
a(
|
||||
{
|
||||
href: markdownUrl,
|
||||
target: linkTarget
|
||||
target: linkTarget,
|
||||
},
|
||||
"Markdown"
|
||||
),
|
||||
". Posts cannot be edited or deleted."
|
||||
". Posts cannot be edited or deleted.",
|
||||
],
|
||||
publishCustomInfo: ({ href }) => [
|
||||
"If you're an advanced user, you can also ",
|
||||
a({ href }, "publish a custom message"),
|
||||
"."
|
||||
".",
|
||||
],
|
||||
publishBasicInfo: ({ href }) => [
|
||||
"If you're not an advanced user, you should ",
|
||||
a({ href }, "publish a post"),
|
||||
"."
|
||||
".",
|
||||
],
|
||||
publishCustom: "Publish custom",
|
||||
|
||||
|
@ -115,13 +115,13 @@ module.exports = {
|
|||
a({ href: markdownUrl }, "Markdown"),
|
||||
". Messages cannot be edited or deleted. To respond to an entire thread, select ",
|
||||
strong("comment"),
|
||||
" instead."
|
||||
" instead.",
|
||||
],
|
||||
// settings
|
||||
settingsIntro: ({ readmeUrl, version }) => [
|
||||
`You're using Oasis ${version}. Check out `,
|
||||
a({ href: readmeUrl }, "the readme"),
|
||||
", configure your theme, or view debugging information below."
|
||||
", configure your theme, or view debugging information below.",
|
||||
],
|
||||
theme: "Theme",
|
||||
themeIntro:
|
||||
|
@ -152,11 +152,11 @@ module.exports = {
|
|||
// posts and comments
|
||||
commentDescription: ({ parentUrl }) => [
|
||||
"commented on ",
|
||||
a({ href: parentUrl }, " thread")
|
||||
a({ href: parentUrl }, " thread"),
|
||||
],
|
||||
replyDescription: ({ parentUrl }) => [
|
||||
"replied to ",
|
||||
a({ href: parentUrl }, " message")
|
||||
a({ href: parentUrl }, " message"),
|
||||
],
|
||||
mysteryDescription: "posted a mysterious message",
|
||||
// misc
|
||||
|
@ -169,7 +169,7 @@ module.exports = {
|
|||
profileImage: "Profile image",
|
||||
profileDescription: "Profile description (Markdown)",
|
||||
hashtagDescription:
|
||||
"Posts from people in your network that reference this hashtag, sorted by recency."
|
||||
"Posts from people in your network that reference this hashtag, sorted by recency.",
|
||||
},
|
||||
/* spell-checker: disable */
|
||||
es: {
|
||||
|
@ -182,7 +182,7 @@ module.exports = {
|
|||
extendedDescription: [
|
||||
"Publicaciones de ",
|
||||
strong("personas que no seguís"),
|
||||
", ordenadas por las más recientes. Quando seguís una persona poderás descargar publicaciones de otras personas que esta siga y esos mensajes aparecen aquí."
|
||||
", ordenadas por las más recientes. Quando seguís una persona poderás descargar publicaciones de otras personas que esta siga y esos mensajes aparecen aquí.",
|
||||
],
|
||||
popular: "Populares",
|
||||
popularDescription: [
|
||||
|
@ -190,32 +190,32 @@ module.exports = {
|
|||
strong("Me Gusta"),
|
||||
" en determinados periodos. Se cuentan los Me Gusta de ",
|
||||
em("todos"),
|
||||
", incluindo aquellos que no seguís. Esta es una lista de publicaciones más populares de tu red de contacto."
|
||||
", incluindo aquellos que no seguís. Esta es una lista de publicaciones más populares de tu red de contacto.",
|
||||
],
|
||||
latestDescription:
|
||||
"Publicaciones que aquellos que seguís, ordenadas por las más recientes.",
|
||||
topics: "Topicos",
|
||||
topicsDescription: [
|
||||
strong("Topicos"),
|
||||
" de las personas que seguís, ordenadas por las más recientes. Seleccioná la hora de una publicación para leer el hilo completo."
|
||||
" de las personas que seguís, ordenadas por las más recientes. Seleccioná la hora de una publicación para leer el hilo completo.",
|
||||
],
|
||||
summaries: "Resumen",
|
||||
summariesDescription: [
|
||||
strong("Topicos y algunos comentarios"),
|
||||
" de las personas que seguís, ordenadas por las más recientes. Seleccioná la hora de una publicación para leer el hilo completo."
|
||||
" de las personas que seguís, ordenadas por las más recientes. Seleccioná la hora de una publicación para leer el hilo completo.",
|
||||
],
|
||||
manualMode: "Modo manual",
|
||||
mentions: "Menciones",
|
||||
mentionsDescription: [
|
||||
strong("Publicaciones de "),
|
||||
strong("cualquier persona"),
|
||||
" que te mencionan, ordenadas por las más recientes. Solo figuran menciones en el formato @mención."
|
||||
" que te mencionan, ordenadas por las más recientes. Solo figuran menciones en el formato @mención.",
|
||||
],
|
||||
private: "Privado",
|
||||
privateDescription: [
|
||||
"Los comentarios más recientes de ",
|
||||
strong("hilos privados que te incluyen"),
|
||||
". Las publicaciones privadas están encriptadas para tu llave privada, y contienen el máximo de 7 destinatarios. No se podrán adicionar nuevos destinarios después que empieze el hilo. Seleccioná la hora de una publicación para leer el hilo completo."
|
||||
". Las publicaciones privadas están encriptadas para tu llave privada, y contienen el máximo de 7 destinatarios. No se podrán adicionar nuevos destinarios después que empieze el hilo. Seleccioná la hora de una publicación para leer el hilo completo.",
|
||||
],
|
||||
// post actions
|
||||
comment: "Comentar",
|
||||
|
@ -239,12 +239,12 @@ module.exports = {
|
|||
publishCustomDescription: [
|
||||
"Compone un mensaje custom usando ",
|
||||
a({ href: "https://en.wikipedia.org/wiki/JSON" }, "JSON"),
|
||||
". Esto puede ser util para prototipar o componer tipos de mensaje que Oasis aún no soporta. Este mensaje no podrá ser editado o borrado."
|
||||
". Esto puede ser util para prototipar o componer tipos de mensaje que Oasis aún no soporta. Este mensaje no podrá ser editado o borrado.",
|
||||
],
|
||||
commentWarning: [
|
||||
" Los mensajes no podrán ser editados o borrados. Para responde a mensajes, seleccione ",
|
||||
strong("Responder"),
|
||||
"."
|
||||
".",
|
||||
],
|
||||
commentPublic: "publico",
|
||||
commentPrivate: "privado",
|
||||
|
@ -253,28 +253,28 @@ module.exports = {
|
|||
strong(`${publicOrPrivate} comentário`),
|
||||
" con ",
|
||||
a({ href: markdownUrl }, "Markdown"),
|
||||
" en este hilo."
|
||||
" en este hilo.",
|
||||
],
|
||||
publishLabel: ({ markdownUrl, linkTarget }) => [
|
||||
"Escribí mensaje publico con ",
|
||||
a(
|
||||
{
|
||||
href: markdownUrl,
|
||||
target: linkTarget
|
||||
target: linkTarget,
|
||||
},
|
||||
"Markdown"
|
||||
),
|
||||
". Los mensajes no podrán ser editados o borrados."
|
||||
". Los mensajes no podrán ser editados o borrados.",
|
||||
],
|
||||
publishCustomInfo: ({ href }) => [
|
||||
"Si sos un usário avanzado, podrás ",
|
||||
a({ href }, "publicar un mensaje custom"),
|
||||
"."
|
||||
".",
|
||||
],
|
||||
publishBasicInfo: ({ href }) => [
|
||||
"Si no sos un usuário avanzado, podés ",
|
||||
a({ href }, "publicar un mensaje basico."),
|
||||
"."
|
||||
".",
|
||||
],
|
||||
publishCustom: "Publicar custom",
|
||||
|
||||
|
@ -285,13 +285,13 @@ module.exports = {
|
|||
a({ href: markdownUrl }, "Markdown"),
|
||||
". Los mensajes no podrán ser editados o borrados. Para responder a todo un hilo, seleccioná ",
|
||||
strong("comentário"),
|
||||
"."
|
||||
".",
|
||||
],
|
||||
// settings
|
||||
settingsIntro: ({ readmeUrl, version }) => [
|
||||
`Estás usando Oasis ${version}. Leé `,
|
||||
a({ href: readmeUrl }, "el Readme"),
|
||||
", configura un tema, o consultá información de debug abajo."
|
||||
", configura un tema, o consultá información de debug abajo.",
|
||||
],
|
||||
theme: "Tema",
|
||||
themeIntro:
|
||||
|
@ -323,11 +323,11 @@ module.exports = {
|
|||
// posts and comments
|
||||
commentDescription: ({ parentUrl }) => [
|
||||
"comentado en el hilo ",
|
||||
a({ href: parentUrl }, "")
|
||||
a({ href: parentUrl }, ""),
|
||||
],
|
||||
replyDescription: ({ parentUrl }) => [
|
||||
"respondido al mensaje ",
|
||||
a({ href: parentUrl }, "")
|
||||
a({ href: parentUrl }, ""),
|
||||
],
|
||||
mysteryDescription: "publicó un mensaje misterioso",
|
||||
// misc
|
||||
|
@ -340,14 +340,14 @@ module.exports = {
|
|||
profileImage: "Imagen de perfil",
|
||||
profileDescription: "Descripción de perfil (Markdown)",
|
||||
hashtagDescription:
|
||||
"Publicaciones de personas en tu red que mencionan este hashtag, ordenadas por las más recientes."
|
||||
"Publicaciones de personas en tu red que mencionan este hashtag, ordenadas por las más recientes.",
|
||||
},
|
||||
de: {
|
||||
extended: "Erweitert",
|
||||
extendedDescription: [
|
||||
"Beiträge von ",
|
||||
strong("Leuten denen du nicht folgst"),
|
||||
", sortiert nach Aktualität. Wenn du jemandem folgst lädst du eventuell auch Beiträge von Leuten herunter denen diese Person folgt, hier erscheinen diese Beiträge."
|
||||
", sortiert nach Aktualität. Wenn du jemandem folgst lädst du eventuell auch Beiträge von Leuten herunter denen diese Person folgt, hier erscheinen diese Beiträge.",
|
||||
],
|
||||
popular: "Beliebt",
|
||||
popularDescription: [
|
||||
|
@ -355,7 +355,7 @@ module.exports = {
|
|||
strong("Herzen"),
|
||||
" in der angegebenen Periode. Herzen werden von ",
|
||||
em("jedem"),
|
||||
" gezählt, auch von Personen denen du nicht folgst. D.h. hier werden Beiträge von deinen Freund*innen angezeigt die in deinem erweiterten Netzwerk populär sind."
|
||||
" gezählt, auch von Personen denen du nicht folgst. D.h. hier werden Beiträge von deinen Freund*innen angezeigt die in deinem erweiterten Netzwerk populär sind.",
|
||||
],
|
||||
latest: "Aktuell",
|
||||
latestDescription:
|
||||
|
@ -363,12 +363,12 @@ module.exports = {
|
|||
topics: "Themen",
|
||||
topicsDescription: [
|
||||
strong("Themen"),
|
||||
" von Leuten denen du folgst, sortiert nach Aktualität. Klicke auf den Zeitstempel eines Beitrages um den Rest des Threads zu sehen."
|
||||
" von Leuten denen du folgst, sortiert nach Aktualität. Klicke auf den Zeitstempel eines Beitrages um den Rest des Threads zu sehen.",
|
||||
],
|
||||
summaries: "Übersicht",
|
||||
summariesDescription: [
|
||||
strong("Themen und einige Kommentare"),
|
||||
" von Leuten denen du folgst, sortiert nach Aktualität. Klicke auf den Zeitstempel eines Beitrages um den Rest des Threads zu sehen."
|
||||
" von Leuten denen du folgst, sortiert nach Aktualität. Klicke auf den Zeitstempel eines Beitrages um den Rest des Threads zu sehen.",
|
||||
],
|
||||
profile: "Profil",
|
||||
manualMode: "Manueller Modus",
|
||||
|
@ -377,13 +377,13 @@ module.exports = {
|
|||
strong("Beiträge in denen du erwähnt wirst"),
|
||||
" von ",
|
||||
strong("allen"),
|
||||
", sortiert nach Aktualität. Manchmal vergessen Leute dich zu @erwähnen, diese Beiträge werden hier nicht erscheinen."
|
||||
", sortiert nach Aktualität. Manchmal vergessen Leute dich zu @erwähnen, diese Beiträge werden hier nicht erscheinen.",
|
||||
],
|
||||
private: "Privat",
|
||||
privateDescription: [
|
||||
"Die letzten Kommentare aus ",
|
||||
strong("privaten Threads die dich beinhalten"),
|
||||
", sortiert nach Aktualität. Private Beiträge werden mit deinem öffentlichen Schlüssel verschlüsselt und haben maximal 7 Empfänger*innen. Empfänger*innen können nicht hinzugefügt werden nachdem ein Thread gestartet wurde. Klicke auf den Zeitstämpel um einen komplette Thread anzuzeigen."
|
||||
", sortiert nach Aktualität. Private Beiträge werden mit deinem öffentlichen Schlüssel verschlüsselt und haben maximal 7 Empfänger*innen. Empfänger*innen können nicht hinzugefügt werden nachdem ein Thread gestartet wurde. Klicke auf den Zeitstämpel um einen komplette Thread anzuzeigen.",
|
||||
],
|
||||
search: "Suche",
|
||||
settings: "Einstellungen",
|
||||
|
@ -409,12 +409,12 @@ module.exports = {
|
|||
publishCustomDescription: [
|
||||
"Veröffentliche eine benutzerdefinierte Nachricht durch das Eingeben von ",
|
||||
a({ href: "https://en.wikipedia.org/wiki/JSON" }, "JSON"),
|
||||
" unten. Dies kann zum Prototyping oder dem veröffentlichen von Nachrichten die Oasis nicht unterstützt nützlich sein. Diese Nachricht kann nicht bearbeitet oder gelöscht werden."
|
||||
" unten. Dies kann zum Prototyping oder dem veröffentlichen von Nachrichten die Oasis nicht unterstützt nützlich sein. Diese Nachricht kann nicht bearbeitet oder gelöscht werden.",
|
||||
],
|
||||
commentWarning: [
|
||||
" Nachrichten können nicht bearbeitet oder gelöscht werden. Um auf eine einzelne Nachricht zu antworten, wähle ",
|
||||
strong("antworten"),
|
||||
" stattdessen."
|
||||
" stattdessen.",
|
||||
],
|
||||
commentPublic: "öffentlichen",
|
||||
commentPrivate: "privaten",
|
||||
|
@ -423,28 +423,28 @@ module.exports = {
|
|||
strong(`${publicOrPrivate} Kommentar`),
|
||||
" in diesem Thread mit ",
|
||||
a({ href: markdownUrl }, "Markdown"),
|
||||
"."
|
||||
".",
|
||||
],
|
||||
publishLabel: ({ markdownUrl, linkTarget }) => [
|
||||
"Verfasse einen neuen öffentlichen Beitrag in ",
|
||||
a(
|
||||
{
|
||||
href: markdownUrl,
|
||||
target: linkTarget
|
||||
target: linkTarget,
|
||||
},
|
||||
"Markdown"
|
||||
),
|
||||
". Beiträge können nicht bearbeitet oder gelöscht werden."
|
||||
". Beiträge können nicht bearbeitet oder gelöscht werden.",
|
||||
],
|
||||
publishCustomInfo: ({ href }) => [
|
||||
"Wenn du ein erfahrener Benutzer bist kannst du auch ",
|
||||
a({ href }, "eine benutzerdefinierte Nachricht veröffentlichen"),
|
||||
"."
|
||||
".",
|
||||
],
|
||||
publishBasicInfo: ({ href }) => [
|
||||
"Wenn du kein erfahrener Benutzer bist, solltest du ",
|
||||
a({ href }, "einen einfachen Beitrag veröffentlichen"),
|
||||
"."
|
||||
".",
|
||||
],
|
||||
publishCustom: "Benutzerdefinierte Veröffentlichung",
|
||||
replyLabel: ({ markdownUrl }) => [
|
||||
|
@ -454,13 +454,13 @@ module.exports = {
|
|||
a({ href: markdownUrl }, "Markdown"),
|
||||
". Nachrichten können nicht bearbeitet oder gelöscht werden. Um auf einen kompletten Thread zu antworten, klicke auf ",
|
||||
strong("kommentieren"),
|
||||
" stattdessen."
|
||||
" stattdessen.",
|
||||
],
|
||||
// settings
|
||||
settingsIntro: ({ readmeUrl, version }) => [
|
||||
`Du verwendest Oasis ${version}. Lese `,
|
||||
a({ href: readmeUrl }, "die Readme"),
|
||||
", konfiguriere dein Theme oder schaue dir Debugging-Informationen weiter unten an."
|
||||
", konfiguriere dein Theme oder schaue dir Debugging-Informationen weiter unten an.",
|
||||
],
|
||||
theme: "Theme",
|
||||
themeIntro:
|
||||
|
@ -491,11 +491,11 @@ module.exports = {
|
|||
// posts and comments
|
||||
commentDescription: ({ parentUrl }) => [
|
||||
"kommentierte auf ",
|
||||
a({ href: parentUrl }, " Thread")
|
||||
a({ href: parentUrl }, " Thread"),
|
||||
],
|
||||
replyDescription: ({ parentUrl }) => [
|
||||
"antwortete auf ",
|
||||
a({ href: parentUrl }, " Nachricht")
|
||||
a({ href: parentUrl }, " Nachricht"),
|
||||
],
|
||||
mysteryDescription: "veröffentlichte eine mysteriöse Nachricht",
|
||||
// misc
|
||||
|
@ -507,6 +507,6 @@ module.exports = {
|
|||
profileName: "Profilname (Text)",
|
||||
profileDescription: "Profilbeschreibung (Markdown)",
|
||||
hashtagDescription:
|
||||
"Beiträge von Leuten in deinem Netzwerk die dieses Hashtag referenzieren, sortiert nach Aktualität."
|
||||
}
|
||||
"Beiträge von Leuten in deinem Netzwerk die dieses Hashtag referenzieren, sortiert nach Aktualität.",
|
||||
},
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ const {
|
|||
summary,
|
||||
textarea,
|
||||
title,
|
||||
ul
|
||||
ul,
|
||||
} = require("hyperaxe");
|
||||
|
||||
const lodash = require("lodash");
|
||||
|
@ -50,7 +50,7 @@ const i18nBase = require("./i18n");
|
|||
let i18n = null;
|
||||
let selectedLanguage = null;
|
||||
|
||||
exports.setLanguage = language => {
|
||||
exports.setLanguage = (language) => {
|
||||
selectedLanguage = language;
|
||||
i18n = Object.assign({}, i18nBase.en, i18nBase[language]);
|
||||
};
|
||||
|
@ -60,7 +60,7 @@ const doctypeString = "<!DOCTYPE html>";
|
|||
|
||||
const THREAD_PREVIEW_LENGTH = 3;
|
||||
|
||||
const toAttributes = obj =>
|
||||
const toAttributes = (obj) =>
|
||||
Object.entries(obj)
|
||||
.map(([key, val]) => `${key}=${val}`)
|
||||
.join(", ");
|
||||
|
@ -83,11 +83,11 @@ const template = (...elements) => {
|
|||
meta({ charset: "utf-8" }),
|
||||
meta({
|
||||
name: "description",
|
||||
content: i18n.oasisDescription
|
||||
content: i18n.oasisDescription,
|
||||
}),
|
||||
meta({
|
||||
name: "viewport",
|
||||
content: toAttributes({ width: "device-width", "initial-scale": 1 })
|
||||
content: toAttributes({ width: "device-width", "initial-scale": 1 }),
|
||||
})
|
||||
),
|
||||
body(
|
||||
|
@ -96,28 +96,28 @@ const template = (...elements) => {
|
|||
navLink({
|
||||
href: "/publish",
|
||||
emoji: "📝",
|
||||
text: i18n.publish
|
||||
text: i18n.publish,
|
||||
}),
|
||||
navLink({
|
||||
href: "/public/latest/extended",
|
||||
emoji: "🗺️",
|
||||
text: i18n.extended
|
||||
text: i18n.extended,
|
||||
}),
|
||||
navLink({
|
||||
href: "/public/popular/day",
|
||||
emoji: "📣",
|
||||
text: i18n.popular
|
||||
text: i18n.popular,
|
||||
}),
|
||||
navLink({ href: "/public/latest", emoji: "🐇", text: i18n.latest }),
|
||||
navLink({
|
||||
href: "/public/latest/topics",
|
||||
emoji: "📖",
|
||||
text: i18n.topics
|
||||
text: i18n.topics,
|
||||
}),
|
||||
navLink({
|
||||
href: "/public/latest/summaries",
|
||||
emoji: "🗒️",
|
||||
text: i18n.summaries
|
||||
text: i18n.summaries,
|
||||
}),
|
||||
navLink({ href: "/profile", emoji: "🐱", text: i18n.profile }),
|
||||
navLink({ href: "/mentions", emoji: "💬", text: i18n.mentions }),
|
||||
|
@ -135,11 +135,11 @@ const template = (...elements) => {
|
|||
return result;
|
||||
};
|
||||
|
||||
const postInAside = msg => {
|
||||
const postInAside = (msg) => {
|
||||
const encoded = {
|
||||
key: encodeURIComponent(msg.key),
|
||||
author: encodeURIComponent(msg.value.author),
|
||||
parent: encodeURIComponent(msg.value.content.root)
|
||||
parent: encodeURIComponent(msg.value.content.root),
|
||||
};
|
||||
|
||||
const url = {
|
||||
|
@ -150,7 +150,7 @@ const postInAside = msg => {
|
|||
avatar: msg.value.meta.author.avatar.url,
|
||||
json: `/json/${encoded.key}`,
|
||||
reply: `/reply/${encoded.key}`,
|
||||
comment: `/comment/${encoded.key}`
|
||||
comment: `/comment/${encoded.key}`,
|
||||
};
|
||||
|
||||
const isPrivate = Boolean(msg.value.meta.private);
|
||||
|
@ -197,16 +197,16 @@ const postInAside = msg => {
|
|||
post: null,
|
||||
comment: i18n.commentDescription({ parentUrl: url.parent }),
|
||||
reply: i18n.replyDescription({ parentUrl: url.parent }),
|
||||
mystery: i18n.mysteryDescription
|
||||
mystery: i18n.mysteryDescription,
|
||||
};
|
||||
|
||||
const isMarkdownEmpty = md => md === "<p>undefined</p>\n";
|
||||
const isMarkdownEmpty = (md) => md === "<p>undefined</p>\n";
|
||||
const articleElement = isMarkdownEmpty(markdownContent)
|
||||
? article(
|
||||
{ class: "content" },
|
||||
pre({
|
||||
innerHTML: highlightJs.highlight("json", JSON.stringify(msg, null, 2))
|
||||
.value
|
||||
.value,
|
||||
})
|
||||
)
|
||||
: article({ class: "content", innerHTML: markdownContent });
|
||||
|
@ -217,7 +217,7 @@ const postInAside = msg => {
|
|||
|
||||
return section(
|
||||
{
|
||||
class: messageClasses.join(" ")
|
||||
class: messageClasses.join(" "),
|
||||
},
|
||||
header(
|
||||
span(
|
||||
|
@ -244,7 +244,7 @@ const postInAside = msg => {
|
|||
name: "voteValue",
|
||||
type: "submit",
|
||||
value: likeButton.value,
|
||||
class: likeButton.class
|
||||
class: likeButton.class,
|
||||
},
|
||||
`❤ ${likeCount}`
|
||||
)
|
||||
|
@ -267,7 +267,7 @@ const postInAside = msg => {
|
|||
const continueThreadComponent = (thread, isComment) => {
|
||||
const encoded = {
|
||||
next: encodeURIComponent(thread[THREAD_PREVIEW_LENGTH + 1].key),
|
||||
parent: encodeURIComponent(thread[0].key)
|
||||
parent: encodeURIComponent(thread[0].key),
|
||||
};
|
||||
const left = thread.length - (THREAD_PREVIEW_LENGTH + 1);
|
||||
let continueLink;
|
||||
|
@ -301,7 +301,7 @@ const postAside = ({ key, value }) => {
|
|||
|
||||
let postsToShow;
|
||||
if (isComment) {
|
||||
const commentPosition = thread.findIndex(msg => msg.key === key);
|
||||
const commentPosition = thread.findIndex((msg) => msg.key === key);
|
||||
postsToShow = thread.slice(
|
||||
commentPosition + 1,
|
||||
Math.min(commentPosition + (THREAD_PREVIEW_LENGTH + 1), thread.length)
|
||||
|
@ -326,7 +326,7 @@ const post = ({ msg, aside = false }) => {
|
|||
const encoded = {
|
||||
key: encodeURIComponent(msg.key),
|
||||
author: encodeURIComponent(msg.value.author),
|
||||
parent: encodeURIComponent(msg.value.content.root)
|
||||
parent: encodeURIComponent(msg.value.content.root),
|
||||
};
|
||||
|
||||
const url = {
|
||||
|
@ -337,7 +337,7 @@ const post = ({ msg, aside = false }) => {
|
|||
avatar: msg.value.meta.author.avatar.url,
|
||||
json: `/json/${encoded.key}`,
|
||||
reply: `/reply/${encoded.key}`,
|
||||
comment: `/comment/${encoded.key}`
|
||||
comment: `/comment/${encoded.key}`,
|
||||
};
|
||||
|
||||
const isPrivate = Boolean(msg.value.meta.private);
|
||||
|
@ -390,7 +390,7 @@ const post = ({ msg, aside = false }) => {
|
|||
post: null,
|
||||
comment: i18n.commentDescription({ parentUrl: url.parent }),
|
||||
reply: i18n.replyDescription({ parentUrl: url.parent }),
|
||||
mystery: i18n.mysteryDescription
|
||||
mystery: i18n.mysteryDescription,
|
||||
};
|
||||
|
||||
const emptyContent = "<p>undefined</p>\n";
|
||||
|
@ -402,7 +402,7 @@ const post = ({ msg, aside = false }) => {
|
|||
innerHTML: highlightJs.highlight(
|
||||
"json",
|
||||
JSON.stringify(msg, null, 2)
|
||||
).value
|
||||
).value,
|
||||
})
|
||||
)
|
||||
: article({ class: "content", innerHTML: markdownContent });
|
||||
|
@ -415,7 +415,7 @@ const post = ({ msg, aside = false }) => {
|
|||
{
|
||||
id: msg.key,
|
||||
class: messageClasses.join(" "),
|
||||
style: `margin-left: ${depth}rem;`
|
||||
style: `margin-left: ${depth}rem;`,
|
||||
},
|
||||
header(
|
||||
span(
|
||||
|
@ -454,7 +454,7 @@ const post = ({ msg, aside = false }) => {
|
|||
name: "voteValue",
|
||||
type: "submit",
|
||||
value: likeButton.value,
|
||||
class: likeButton.class
|
||||
class: likeButton.class,
|
||||
},
|
||||
`❤ ${likeCount}`
|
||||
)
|
||||
|
@ -481,7 +481,7 @@ exports.editProfileView = ({ name, description }) =>
|
|||
{
|
||||
action: "/profile/edit",
|
||||
method: "POST",
|
||||
enctype: "multipart/form-data"
|
||||
enctype: "multipart/form-data",
|
||||
},
|
||||
label(
|
||||
i18n.profileImage,
|
||||
|
@ -493,14 +493,14 @@ exports.editProfileView = ({ name, description }) =>
|
|||
textarea(
|
||||
{
|
||||
autofocus: true,
|
||||
name: "description"
|
||||
name: "description",
|
||||
},
|
||||
description
|
||||
)
|
||||
),
|
||||
button(
|
||||
{
|
||||
type: "submit"
|
||||
type: "submit",
|
||||
},
|
||||
i18n.submit
|
||||
)
|
||||
|
@ -514,7 +514,7 @@ exports.authorView = ({
|
|||
feedId,
|
||||
messages,
|
||||
name,
|
||||
relationship
|
||||
relationship,
|
||||
}) => {
|
||||
const mention = `[@${name}](${feedId})`;
|
||||
const markdownMention = highlightJs.highlight("markdown", mention).value;
|
||||
|
@ -532,11 +532,11 @@ exports.authorView = ({
|
|||
: form(
|
||||
{
|
||||
action: `/${contactFormType}/${encodeURIComponent(feedId)}`,
|
||||
method: "post"
|
||||
method: "post",
|
||||
},
|
||||
button(
|
||||
{
|
||||
type: "submit"
|
||||
type: "submit",
|
||||
},
|
||||
contactFormType
|
||||
)
|
||||
|
@ -579,7 +579,7 @@ exports.authorView = ({
|
|||
),
|
||||
pre({
|
||||
class: "md-mention",
|
||||
innerHTML: markdownMention
|
||||
innerHTML: markdownMention,
|
||||
}),
|
||||
description !== "" ? article({ innerHTML: markdown(description) }) : null,
|
||||
footer(
|
||||
|
@ -594,7 +594,7 @@ exports.authorView = ({
|
|||
|
||||
return template(
|
||||
prefix,
|
||||
messages.map(msg => post({ msg }))
|
||||
messages.map((msg) => post({ msg }))
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -602,7 +602,7 @@ exports.commentView = async ({ messages, myFeedId, parentMessage }) => {
|
|||
let markdownMention;
|
||||
|
||||
const messageElements = await Promise.all(
|
||||
messages.reverse().map(message => {
|
||||
messages.reverse().map((message) => {
|
||||
debug("%O", message);
|
||||
const authorName = message.value.meta.author.name;
|
||||
const authorFeedId = message.value.author;
|
||||
|
@ -636,13 +636,13 @@ exports.commentView = async ({ messages, myFeedId, parentMessage }) => {
|
|||
{
|
||||
autofocus: true,
|
||||
required: true,
|
||||
name: "text"
|
||||
name: "text",
|
||||
},
|
||||
isPrivate ? null : markdownMention
|
||||
),
|
||||
button(
|
||||
{
|
||||
type: "submit"
|
||||
type: "submit",
|
||||
},
|
||||
i18n.comment
|
||||
)
|
||||
|
@ -654,7 +654,7 @@ exports.mentionsView = ({ messages }) => {
|
|||
return messageListView({
|
||||
messages,
|
||||
viewTitle: i18n.mentions,
|
||||
viewDescription: i18n.mentionsDescription
|
||||
viewDescription: i18n.mentionsDescription,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -662,7 +662,7 @@ exports.privateView = ({ messages }) => {
|
|||
return messageListView({
|
||||
messages,
|
||||
viewTitle: i18n.private,
|
||||
viewDescription: i18n.privateDescription
|
||||
viewDescription: i18n.privateDescription,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -680,7 +680,7 @@ exports.publishCustomView = async () => {
|
|||
{
|
||||
autofocus: true,
|
||||
required: true,
|
||||
name: "text"
|
||||
name: "text",
|
||||
},
|
||||
"{\n",
|
||||
' "type": "test",\n',
|
||||
|
@ -689,7 +689,7 @@ exports.publishCustomView = async () => {
|
|||
),
|
||||
button(
|
||||
{
|
||||
type: "submit"
|
||||
type: "submit",
|
||||
},
|
||||
i18n.submit
|
||||
)
|
||||
|
@ -700,7 +700,7 @@ exports.publishCustomView = async () => {
|
|||
};
|
||||
|
||||
exports.threadView = ({ messages }) =>
|
||||
template(messages.map(msg => post({ msg })));
|
||||
template(messages.map((msg) => post({ msg })));
|
||||
|
||||
exports.markdownView = ({ text }) => {
|
||||
const rawHtml = md.render(text);
|
||||
|
@ -726,7 +726,7 @@ exports.publishView = () => {
|
|||
name: "contentWarning",
|
||||
type: "text",
|
||||
class: "contentWarning",
|
||||
placeholder: i18n.contentWarningPlaceholder
|
||||
placeholder: i18n.contentWarningPlaceholder,
|
||||
})
|
||||
),
|
||||
button({ type: "submit" }, i18n.submit)
|
||||
|
@ -739,7 +739,7 @@ exports.publishView = () => {
|
|||
exports.settingsView = ({ status, peers, theme, themeNames, version }) => {
|
||||
const max = status.sync.since;
|
||||
|
||||
const progressElements = Object.entries(status.sync.plugins).map(e => {
|
||||
const progressElements = Object.entries(status.sync.plugins).map((e) => {
|
||||
const [key, val] = e;
|
||||
const id = `progress-${key}`;
|
||||
return div(label(key, progress({ id, value: val, max }, val)));
|
||||
|
@ -763,7 +763,7 @@ exports.settingsView = ({ status, peers, theme, themeNames, version }) => {
|
|||
const connButtons = div({ class: "form-button-group" }, [
|
||||
startButton,
|
||||
restartButton,
|
||||
stopButton
|
||||
stopButton,
|
||||
]);
|
||||
|
||||
const peerList = (peers || []).map(([, data]) => {
|
||||
|
@ -775,7 +775,7 @@ exports.settingsView = ({ status, peers, theme, themeNames, version }) => {
|
|||
);
|
||||
});
|
||||
|
||||
const themeElements = themeNames.map(cur => {
|
||||
const themeElements = themeNames.map((cur) => {
|
||||
const isCurrentTheme = cur === theme;
|
||||
if (isCurrentTheme) {
|
||||
return option({ value: cur, selected: true }, cur);
|
||||
|
@ -800,18 +800,18 @@ exports.settingsView = ({ status, peers, theme, themeNames, version }) => {
|
|||
"0C",
|
||||
"0D",
|
||||
"0E",
|
||||
"0F"
|
||||
"0F",
|
||||
];
|
||||
|
||||
const base16Elements = base16.map(base =>
|
||||
const base16Elements = base16.map((base) =>
|
||||
div({
|
||||
style: {
|
||||
"background-color": `var(--base${base})`,
|
||||
width: `${(1 / base16.length) * 100}%`,
|
||||
height: "1em",
|
||||
"margin-top": "1em",
|
||||
display: "inline-block"
|
||||
}
|
||||
display: "inline-block",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -853,7 +853,7 @@ exports.settingsView = ({ status, peers, theme, themeNames, version }) => {
|
|||
languageOption("en", "English"),
|
||||
languageOption("es", "Español"),
|
||||
/* cspell:disable-next-line */
|
||||
languageOption("de", "Deutsch")
|
||||
languageOption("de", "Deutsch"),
|
||||
]),
|
||||
button({ type: "submit" }, i18n.setLanguage)
|
||||
),
|
||||
|
@ -882,9 +882,9 @@ exports.likesView = async ({ messages, feed, name }) => {
|
|||
|
||||
return template(
|
||||
viewInfoBox({
|
||||
viewTitle: span(authorLink, i18n.likedBy)
|
||||
viewTitle: span(authorLink, i18n.likedBy),
|
||||
}),
|
||||
messages.map(msg => post({ msg }))
|
||||
messages.map((msg) => post({ msg }))
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -894,11 +894,11 @@ const messageListView = ({
|
|||
viewDescription = null,
|
||||
viewElements = null,
|
||||
// If `aside = true`, it will show a few comments in the thread.
|
||||
aside = null
|
||||
aside = null,
|
||||
}) => {
|
||||
return template(
|
||||
section(h1(viewTitle), p(viewDescription), viewElements),
|
||||
messages.map(msg => post({ msg, aside }))
|
||||
messages.map((msg) => post({ msg, aside }))
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -907,7 +907,7 @@ exports.popularView = ({ messages, prefix }) => {
|
|||
messages,
|
||||
viewElements: prefix,
|
||||
viewTitle: i18n.popular,
|
||||
viewDescription: i18n.popularDescription
|
||||
viewDescription: i18n.popularDescription,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -915,7 +915,7 @@ exports.extendedView = ({ messages }) => {
|
|||
return messageListView({
|
||||
messages,
|
||||
viewTitle: i18n.extended,
|
||||
viewDescription: i18n.extendedDescription
|
||||
viewDescription: i18n.extendedDescription,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -923,7 +923,7 @@ exports.latestView = ({ messages }) => {
|
|||
return messageListView({
|
||||
messages,
|
||||
viewTitle: i18n.latest,
|
||||
viewDescription: i18n.latestDescription
|
||||
viewDescription: i18n.latestDescription,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -931,7 +931,7 @@ exports.topicsView = ({ messages }) => {
|
|||
return messageListView({
|
||||
messages,
|
||||
viewTitle: i18n.topics,
|
||||
viewDescription: i18n.topicsDescription
|
||||
viewDescription: i18n.topicsDescription,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -940,7 +940,7 @@ exports.summaryView = ({ messages }) => {
|
|||
messages,
|
||||
viewTitle: i18n.summaries,
|
||||
viewDescription: i18n.summariesDescription,
|
||||
aside: true
|
||||
aside: true,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -952,7 +952,7 @@ exports.replyView = async ({ messages, myFeedId }) => {
|
|||
let markdownMention;
|
||||
|
||||
const messageElements = await Promise.all(
|
||||
messages.reverse().map(message => {
|
||||
messages.reverse().map((message) => {
|
||||
debug("%O", message);
|
||||
const authorName = message.value.meta.author.name;
|
||||
const authorFeedId = message.value.author;
|
||||
|
@ -975,13 +975,13 @@ exports.replyView = async ({ messages, myFeedId }) => {
|
|||
{
|
||||
autofocus: true,
|
||||
required: true,
|
||||
name: "text"
|
||||
name: "text",
|
||||
},
|
||||
markdownMention
|
||||
),
|
||||
button(
|
||||
{
|
||||
type: "submit"
|
||||
type: "submit",
|
||||
},
|
||||
i18n.reply
|
||||
)
|
||||
|
@ -994,7 +994,7 @@ exports.searchView = ({ messages, query }) => {
|
|||
name: "query",
|
||||
required: false,
|
||||
type: "search",
|
||||
value: query
|
||||
value: query,
|
||||
});
|
||||
|
||||
// - Minimum length of 3 because otherwise SSB-Search hangs forever. :)
|
||||
|
@ -1012,20 +1012,20 @@ exports.searchView = ({ messages, query }) => {
|
|||
label(i18n.searchLabel, searchInput),
|
||||
button(
|
||||
{
|
||||
type: "submit"
|
||||
type: "submit",
|
||||
},
|
||||
i18n.submit
|
||||
)
|
||||
)
|
||||
),
|
||||
messages.map(msg => post({ msg }))
|
||||
messages.map((msg) => post({ msg }))
|
||||
);
|
||||
};
|
||||
|
||||
exports.hashtagView = ({ messages, hashtag }) => {
|
||||
return template(
|
||||
section(h1(`#${hashtag}`), p(i18n.hashtagDescription)),
|
||||
messages.map(msg => post({ msg }))
|
||||
messages.map((msg) => post({ msg }))
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1041,11 +1041,11 @@ exports.indexingView = ({ percent }) => {
|
|||
meta({ charset: "utf-8" }),
|
||||
meta({
|
||||
name: "description",
|
||||
content: i18n.oasisDescription
|
||||
content: i18n.oasisDescription,
|
||||
}),
|
||||
meta({
|
||||
name: "viewport",
|
||||
content: toAttributes({ width: "device-width", "initial-scale": 1 })
|
||||
content: toAttributes({ width: "device-width", "initial-scale": 1 }),
|
||||
}),
|
||||
meta({ "http-equiv": "refresh", content: 10 })
|
||||
),
|
||||
|
|
|
@ -6,7 +6,7 @@ const ssbRef = require("ssb-ref");
|
|||
const { span } = require("hyperaxe");
|
||||
|
||||
/** @param {{ link: string}[]} mentions */
|
||||
const toUrl = mentions => {
|
||||
const toUrl = (mentions) => {
|
||||
/** @type {{name: string, link: string}[]} */
|
||||
const mentionNames = [];
|
||||
|
||||
|
@ -21,7 +21,7 @@ const toUrl = mentions => {
|
|||
ssbMessages.links(mentions, "feed").forEach(handleLink);
|
||||
|
||||
/** @param {string} ref */
|
||||
const urlHandler = ref => {
|
||||
const urlHandler = (ref) => {
|
||||
// @mentions
|
||||
const found = mentionNames.find(({ name }) => name === ref);
|
||||
if (found !== undefined) {
|
||||
|
@ -53,5 +53,5 @@ const toUrl = mentions => {
|
|||
module.exports = (input, mentions = []) =>
|
||||
md.block(input, {
|
||||
toUrl: toUrl(mentions),
|
||||
emoji: character => span({ class: "emoji" }, character).outerHTML
|
||||
emoji: (character) => span({ class: "emoji" }, character).outerHTML,
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue