Add private vanishing messages
This commit is contained in:
parent
929a46d8cb
commit
d207b512a3
|
@ -66,11 +66,17 @@ router.get("/", async (_req, res) => {
|
||||||
res.redirect("/about");
|
res.redirect("/about");
|
||||||
}
|
}
|
||||||
|
|
||||||
const [posts, friends] = await Promise.all([
|
const [posts, friends, vanishingMessages] = await Promise.all([
|
||||||
queries.getPosts(ssbServer, context.profile),
|
queries.getPosts(ssbServer, context.profile),
|
||||||
queries.getFriends(ssbServer, context.profile),
|
queries.getFriends(ssbServer, context.profile),
|
||||||
|
queries.getVanishingMessages(ssbServer, context.profile),
|
||||||
]);
|
]);
|
||||||
res.render("index", { posts, friends });
|
res.render("index", {
|
||||||
|
posts,
|
||||||
|
friends,
|
||||||
|
vanishingMessages,
|
||||||
|
profile: context.profile,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/profile/:id", async (req, res) => {
|
router.get("/profile/:id", async (req, res) => {
|
||||||
|
@ -101,12 +107,25 @@ router.post("/publish", async (req, res) => {
|
||||||
|
|
||||||
router.post("/profile/:id/publish", async (req, res) => {
|
router.post("/profile/:id/publish", async (req, res) => {
|
||||||
const id = req.params.id;
|
const id = req.params.id;
|
||||||
|
const visibility = req.body.visibility;
|
||||||
|
console.log("req.body", req.body);
|
||||||
|
|
||||||
await ssbServer.publish({
|
if (visibility == "vanishing") {
|
||||||
type: "post",
|
await ssbServer.private.publish(
|
||||||
text: req.body.message,
|
{
|
||||||
root: id,
|
type: "post",
|
||||||
});
|
text: req.body.message,
|
||||||
|
root: id,
|
||||||
|
},
|
||||||
|
[id]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await ssbServer.publish({
|
||||||
|
type: "post",
|
||||||
|
text: req.body.message,
|
||||||
|
root: id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
res.redirect("/profile/" + id);
|
res.redirect("/profile/" + id);
|
||||||
});
|
});
|
||||||
|
|
|
@ -76,6 +76,7 @@ const getPosts = (ssbServer, profile) =>
|
||||||
{
|
{
|
||||||
$filter: {
|
$filter: {
|
||||||
value: {
|
value: {
|
||||||
|
private: { $not: true },
|
||||||
content: {
|
content: {
|
||||||
root: profile.id,
|
root: profile.id,
|
||||||
},
|
},
|
||||||
|
@ -92,6 +93,7 @@ const getPosts = (ssbServer, profile) =>
|
||||||
$filter: {
|
$filter: {
|
||||||
value: {
|
value: {
|
||||||
author: profile.id,
|
author: profile.id,
|
||||||
|
private: { $not: true },
|
||||||
content: {
|
content: {
|
||||||
type: "post",
|
type: "post",
|
||||||
root: { $not: true },
|
root: { $not: true },
|
||||||
|
@ -115,6 +117,64 @@ const getPosts = (ssbServer, profile) =>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getVanishingMessages = (ssbServer, profile) =>
|
||||||
|
debug("Fetching vanishing messages") ||
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
pull(
|
||||||
|
// @ts-ignore
|
||||||
|
cat([
|
||||||
|
ssbServer.query.read({
|
||||||
|
reverse: true,
|
||||||
|
query: [
|
||||||
|
{
|
||||||
|
$filter: {
|
||||||
|
value: {
|
||||||
|
private: true,
|
||||||
|
content: {
|
||||||
|
root: profile.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
limit: 100,
|
||||||
|
}),
|
||||||
|
ssbServer.query.read({
|
||||||
|
reverse: true,
|
||||||
|
query: [
|
||||||
|
{
|
||||||
|
$filter: {
|
||||||
|
value: {
|
||||||
|
author: profile.id,
|
||||||
|
private: true,
|
||||||
|
content: {
|
||||||
|
type: "post",
|
||||||
|
root: { $not: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
limit: 100,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
pull.filter(
|
||||||
|
(msg) =>
|
||||||
|
msg.value.content.type == "post" &&
|
||||||
|
(msg.value.content.root ||
|
||||||
|
msg.value.content.recps.includes(profile.id))
|
||||||
|
),
|
||||||
|
paramap(mapProfiles(ssbServer)),
|
||||||
|
pull.collect((err, msgs) => {
|
||||||
|
debug("Done fetching vanishing messages");
|
||||||
|
const entries = msgs.map((x) => x.value);
|
||||||
|
|
||||||
|
if (err) return reject(err);
|
||||||
|
return resolve(entries);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const searchPeople = (ssbServer, search) =>
|
const searchPeople = (ssbServer, search) =>
|
||||||
debug("Searching people") ||
|
debug("Searching people") ||
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
|
@ -242,4 +302,5 @@ module.exports = {
|
||||||
getFriends,
|
getFriends,
|
||||||
getAllEntries,
|
getAllEntries,
|
||||||
getProfile,
|
getProfile,
|
||||||
|
getVanishingMessages,
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,7 +16,8 @@ Server.use(require("ssb-master"))
|
||||||
.use(require("ssb-device-address"))
|
.use(require("ssb-device-address"))
|
||||||
.use(require("ssb-identities"))
|
.use(require("ssb-identities"))
|
||||||
.use(require("ssb-peer-invites"))
|
.use(require("ssb-peer-invites"))
|
||||||
.use(require("ssb-blobs"));
|
.use(require("ssb-blobs"))
|
||||||
|
.use(require("ssb-private"));
|
||||||
|
|
||||||
const server = Server(config);
|
const server = Server(config);
|
||||||
console.log("SSB server started at", config.port);
|
console.log("SSB server started at", config.port);
|
||||||
|
|
|
@ -2711,6 +2711,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ssb-private": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ssb-private/-/ssb-private-0.2.3.tgz",
|
||||||
|
"integrity": "sha512-SiLBKOB1hxkrohzOrRWURlzj6HvPFvr9LLd5P5I5C5KU/RtaWe79nYuFgjUFJFnjWw7X4szCy32/EZMihV1l/Q==",
|
||||||
|
"requires": {
|
||||||
|
"base64-url": "^2.2.0",
|
||||||
|
"explain-error": "^1.0.4",
|
||||||
|
"flumeview-query": "^6.1.0",
|
||||||
|
"pull-stream": "^3.6.7",
|
||||||
|
"ssb-keys": "^7.0.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ssb-query": {
|
"ssb-query": {
|
||||||
"version": "2.4.3",
|
"version": "2.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/ssb-query/-/ssb-query-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/ssb-query/-/ssb-query-2.4.3.tgz",
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
"ssb-keys": "^7.2.2",
|
"ssb-keys": "^7.2.2",
|
||||||
"ssb-master": "^1.0.3",
|
"ssb-master": "^1.0.3",
|
||||||
"ssb-peer-invites": "^2.0.2",
|
"ssb-peer-invites": "^2.0.2",
|
||||||
|
"ssb-private": "^0.2.3",
|
||||||
"ssb-query": "^2.4.3",
|
"ssb-query": "^2.4.3",
|
||||||
"ssb-replicate": "^1.3.2",
|
"ssb-replicate": "^1.3.2",
|
||||||
"ssb-server": "^15.2.0"
|
"ssb-server": "^15.2.0"
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
const messages = document.querySelectorAll(".vanishing-message");
|
||||||
|
messages.forEach((message) => {
|
||||||
|
message.addEventListener("click", () => {
|
||||||
|
const overlay = message.parentElement.querySelector(".overlay");
|
||||||
|
const modal = message.parentElement.querySelector(".modal");
|
||||||
|
const closeButton = message.parentElement.querySelector(".modal-close");
|
||||||
|
|
||||||
|
overlay.style.display = "block";
|
||||||
|
modal.style.display = "block";
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
const parent = modal.parentElement;
|
||||||
|
parent.parentElement.removeChild(parent);
|
||||||
|
if (document.querySelectorAll(".vanishing-message").length == 0) {
|
||||||
|
document.querySelector(".vanishing-messages").style.display = "none";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
overlay.addEventListener("click", onClose);
|
||||||
|
closeButton.addEventListener("click", onClose);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,9 +1,25 @@
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.3em;
|
line-height: 1.3em;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
button {
|
||||||
|
font-size: 14px;
|
||||||
|
background: #ddd;
|
||||||
|
color: #5f5f5f;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background: #959eab;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
header {
|
header {
|
||||||
padding: 0 30px;
|
padding: 0 30px;
|
||||||
border-bottom: 1px solid #666;
|
border-bottom: 1px solid #666;
|
||||||
|
@ -70,7 +86,7 @@ h1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.wall {
|
.wall {
|
||||||
padding: 20px;
|
padding: 0 20px;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,3 +122,57 @@ h1 {
|
||||||
.profile-pic {
|
.profile-pic {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.vanishing-message {
|
||||||
|
background: none;
|
||||||
|
width: 84px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #333;
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 2;
|
||||||
|
background: #fff;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
min-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
padding: 10px;
|
||||||
|
background: #fffbf4;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
</main>
|
</main>
|
||||||
|
<script src="/js/index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<div class="post">
|
||||||
|
<div>
|
||||||
|
<img src="<%= profileImageUrl(post.authorProfile) %>" class="post-profile-pic" />
|
||||||
|
</div>
|
||||||
|
<div class="post-content">
|
||||||
|
<div class="content-header">
|
||||||
|
<%= post.authorProfile.name %>
|
||||||
|
</div>
|
||||||
|
<div class="content-body">
|
||||||
|
<%= post.content.text.slice(0, 140) %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,27 +1,66 @@
|
||||||
<%- include('_header') %>
|
<%- include('_header') %>
|
||||||
|
|
||||||
<h1>Home</h1>
|
<div class="columns">
|
||||||
|
<div class="about">
|
||||||
|
<img class="profile-pic" src="<%= profileImageUrl(profile) %>" />
|
||||||
|
<h1><%= profile.name %></h1>
|
||||||
|
|
||||||
<form action="/publish" method="POST">
|
<%= profile.description %>
|
||||||
<textarea name="message"></textarea>
|
|
||||||
<input type="submit" value="Send" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<% posts.map(entry => { %>
|
<h2>Friends</h2>
|
||||||
<div><%= entry.authorProfile.name %> (<%= entry.author.slice(0, 8) %>): <%= entry.content.text %></div>
|
|
||||||
<hr />
|
|
||||||
<% }) %>
|
|
||||||
|
|
||||||
<h2>Friends</h2>
|
<ul>
|
||||||
|
<% friends.map(friend => { %>
|
||||||
|
<li>
|
||||||
|
<a href="<%= profileUrl(friend.content.contact) %>">
|
||||||
|
<%= friend.content.contactProfile?.name %> (<%= friend.content.contact.slice(0, 8) %>)
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<% }) %>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<ul>
|
</div>
|
||||||
<% friends.map(friend => { %>
|
|
||||||
<li>
|
<div class="wall">
|
||||||
<a href="<%= profileUrl(friend.content.contact) %>">
|
<% if (vanishingMessages.length > 0) { %>
|
||||||
<%= friend.content.contactProfile && friend.content.contactProfile.name %> (<%= friend.content.contact.slice(0, 8) %>)
|
<div class="vanishing-messages" style="padding-bottom: 20px">
|
||||||
</a>
|
<h2>Vanishing Messages</h2>
|
||||||
</li>
|
<% vanishingMessages.map(post => { %>
|
||||||
<% }) %>
|
<span>
|
||||||
</ul>
|
<button class="vanishing-message">
|
||||||
|
<div><img src="<%= profileImageUrl(post.authorProfile) %>" class="post-profile-pic" /></div>
|
||||||
|
<div><%= post.authorProfile.name %></div>
|
||||||
|
</button>
|
||||||
|
<div class="overlay"></div>
|
||||||
|
<div class="modal">
|
||||||
|
<div class="modal-header">
|
||||||
|
<img src="<%= profileImageUrl(post.authorProfile) %>" class="post-profile-pic" style="padding-right: 10px" />
|
||||||
|
<%= post.authorProfile.name %>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<%= post.content.text %>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
after you close this box the message will be gone forever
|
||||||
|
<button class="modal-close">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
<% }) %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<h2>Your Wall</h2>
|
||||||
|
|
||||||
|
<form action="/publish" method="POST">
|
||||||
|
<textarea name="message"></textarea>
|
||||||
|
<input type="submit" value="Send" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<% posts.map(post => { %>
|
||||||
|
<%- include('_post', { post }) %>
|
||||||
|
<% }) %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<%- include('_footer') %>
|
<%- include('_footer') %>
|
|
@ -22,27 +22,25 @@
|
||||||
|
|
||||||
<div class="wall">
|
<div class="wall">
|
||||||
<h1><%= profile.name %>'s Wall</h1>
|
<h1><%= profile.name %>'s Wall</h1>
|
||||||
<!--
|
|
||||||
<h2>Leave <%= profile.name %> a message</h2>
|
<h2>Leave <%= profile.name %> a message</h2>
|
||||||
<form action="<%= profileUrl(profile.id, "/publish") %>" method="POST">
|
<form action="<%= profileUrl(profile.id, "/publish") %>" method="POST">
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="visibility" value="public">
|
||||||
|
Public
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="visibility" value="vanishing">
|
||||||
|
Vanishing
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<textarea name="message"></textarea>
|
<textarea name="message"></textarea>
|
||||||
<input type="submit" value="Send" />
|
<input type="submit" value="Send" />
|
||||||
</form> -->
|
</form>
|
||||||
|
|
||||||
<% posts.map(entry => { %>
|
<% posts.map(post => { %>
|
||||||
<div class="post">
|
<%- include('_post', { post }) %>
|
||||||
<div>
|
|
||||||
<img src="<%= profileImageUrl(entry.authorProfile) %>" class="post-profile-pic" />
|
|
||||||
</div>
|
|
||||||
<div class="post-content">
|
|
||||||
<div class="content-header">
|
|
||||||
<%= entry.authorProfile.name %>
|
|
||||||
</div>
|
|
||||||
<div class="content-body">
|
|
||||||
<%= entry.content.text.slice(0, 140) %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue