@state-less/leap-backend
Version:
A collection of open source fullstack services
391 lines (389 loc) • 20.3 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Post = exports.Platform = exports.ForumPolicies = exports.Forum = exports.Answer = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
var _reactServer = require("@state-less/react-server");
var _uuid = require("uuid");
var _ServerSideProps = require("../ServerSideProps");
var _Comments = require("../Comments");
var _Votings = require("../Votings");
var _config = require("../../lib/config");
var _ViewCounter = require("../ViewCounter");
var _Reactions = require("../Reactions");
var _jsxRuntime = require("@state-less/react-server/dist/jsxRenderer/jsx-runtime");
var _excluded = ["id", "deleteAnswer", "users"],
_excluded2 = ["id", "deletePost", "approvePost", "setPostSticky", "users"];
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var Answer = exports.Answer = function Answer(_ref, _ref2) {
var _post$owner, _post$owner2, _user, _post$owner3, _user2, _post$owner4, _user3, _post$owner5, _user4, _user5, _user6;
var id = _ref.id,
deleteAnswer = _ref.deleteAnswer,
users = _ref.users,
initialAnswer = (0, _objectWithoutProperties2["default"])(_ref, _excluded);
var context = _ref2.context;
var user = null;
if ((0, _reactServer.isClientContext)(context)) try {
user = (0, _reactServer.authenticate)(context.headers, _config.JWT_SECRET);
} catch (e) {}
var _useState = (0, _reactServer.useState)(initialAnswer, {
key: 'answer',
scope: id
}),
_useState2 = (0, _slicedToArray2["default"])(_useState, 2),
post = _useState2[0],
setPost = _useState2[1];
var _useState3 = (0, _reactServer.useState)(false, {
key: 'deleted',
scope: id
}),
_useState4 = (0, _slicedToArray2["default"])(_useState3, 2),
deleted = _useState4[0],
setDeleted = _useState4[1];
var setBody = function setBody(body) {
if (typeof body !== 'string') throw new Error('Body must be a string');
if (deleted) throw new Error('Cannot edit a deleted post');
setPost(_objectSpread(_objectSpread({}, post), {}, {
body: body
}));
};
var del = function del(id) {
setDeleted(true);
deleteAnswer();
};
return (0, _jsxRuntime.jsxs)(_ServerSideProps.ServerSideProps, _objectSpread(_objectSpread({}, post), {}, {
deleted: deleted,
setBody: setBody,
owner: {
id: (_post$owner = post.owner) === null || _post$owner === void 0 ? void 0 : _post$owner.id,
name: (_post$owner2 = post.owner) === null || _post$owner2 === void 0 || (_post$owner2 = _post$owner2.strategies) === null || _post$owner2 === void 0 || (_post$owner2 = _post$owner2[(_user = user) === null || _user === void 0 ? void 0 : _user.strategy]) === null || _post$owner2 === void 0 ? void 0 : _post$owner2.decoded.name,
picture: (_post$owner3 = post.owner) === null || _post$owner3 === void 0 || (_post$owner3 = _post$owner3.strategies) === null || _post$owner3 === void 0 || (_post$owner3 = _post$owner3[(_user2 = user) === null || _user2 === void 0 ? void 0 : _user2.strategy]) === null || _post$owner3 === void 0 ? void 0 : _post$owner3.decoded.picture,
email: (_post$owner4 = post.owner) === null || _post$owner4 === void 0 || (_post$owner4 = _post$owner4.strategies) === null || _post$owner4 === void 0 || (_post$owner4 = _post$owner4[(_user3 = user) === null || _user3 === void 0 ? void 0 : _user3.strategy]) === null || _post$owner4 === void 0 ? void 0 : _post$owner4.email
},
del: del,
canDelete: (post === null || post === void 0 || (_post$owner5 = post.owner) === null || _post$owner5 === void 0 ? void 0 : _post$owner5.id) === ((_user4 = user) === null || _user4 === void 0 ? void 0 : _user4.id) || users.includes((_user5 = user) === null || _user5 === void 0 || (_user5 = _user5.strategies) === null || _user5 === void 0 || (_user5 = _user5[(_user6 = user) === null || _user6 === void 0 ? void 0 : _user6.strategy]) === null || _user5 === void 0 ? void 0 : _user5.email),
children: [(0, _jsxRuntime.jsx)(_Votings.Votings, {
policies: [_Votings.VotingPolicies.SingleVote]
}, "answer-".concat(id, "-votings")), (0, _jsxRuntime.jsx)(_Comments.Comments, {}, "answer-".concat(id, "-comments")), (0, _jsxRuntime.jsx)(_Reactions.Reactions, {
policies: [_Reactions.ReactionPolicies.SingleVote],
values: _Reactions.reactionsWhiteList
}, "answer-".concat(id, "-reactions"))]
}), "answer-".concat(id, "-props"));
};
var Post = exports.Post = function Post(_ref3, _ref4) {
var _context$headers, _user7, _user8, _post$owner6, _user9, _post$owner7, _post$owner8, _user11, _post$owner9, _user12, _post$owner10, _user13, _user14, _user15;
var id = _ref3.id,
deletePost = _ref3.deletePost,
approvePost = _ref3.approvePost,
setPostSticky = _ref3.setPostSticky,
users = _ref3.users,
initialPost = (0, _objectWithoutProperties2["default"])(_ref3, _excluded2);
var context = _ref4.context;
var user = null;
var clientId = (context === null || context === void 0 || (_context$headers = context.headers) === null || _context$headers === void 0 ? void 0 : _context$headers['x-unique-id']) || 'server';
if ((0, _reactServer.isClientContext)(context)) try {
user = (0, _reactServer.authenticate)(context.headers, _config.JWT_SECRET);
} catch (e) {}
var _useState5 = (0, _reactServer.useState)(initialPost, {
key: 'post',
scope: id,
storeInitialState: true
}),
_useState6 = (0, _slicedToArray2["default"])(_useState5, 2),
post = _useState6[0],
setPost = _useState6[1];
var _useState7 = (0, _reactServer.useState)([], {
key: 'answers',
scope: id
}),
_useState8 = (0, _slicedToArray2["default"])(_useState7, 2),
answers = _useState8[0],
setAnswers = _useState8[1];
var createAnswer = function createAnswer(_ref5) {
var body = _ref5.body;
var answer = {
id: (0, _uuid.v4)(),
owner: user,
body: body
};
setAnswers([].concat((0, _toConsumableArray2["default"])(answers), [answer]));
return answer;
};
var setBody = function setBody(body) {
if (typeof body !== 'string') throw new Error('Body must be a string');
if (post.deleted) throw new Error('Cannot edit a deleted post');
setPost(_objectSpread(_objectSpread({}, post), {}, {
body: body
}));
};
var del = function del(id) {
setPost(_objectSpread(_objectSpread({}, post), {}, {
deleted: true
}));
deletePost();
};
var isAdmin = users.includes((_user7 = user) === null || _user7 === void 0 || (_user7 = _user7.strategies) === null || _user7 === void 0 || (_user7 = _user7[(_user8 = user) === null || _user8 === void 0 ? void 0 : _user8.strategy]) === null || _user7 === void 0 ? void 0 : _user7.email);
var isOwner = (post === null || post === void 0 || (_post$owner6 = post.owner) === null || _post$owner6 === void 0 ? void 0 : _post$owner6.id) === (((_user9 = user) === null || _user9 === void 0 ? void 0 : _user9.id) || clientId);
var isApproved = post === null || post === void 0 ? void 0 : post.approved;
var passProps = {
approved: isApproved
};
if (isAdmin || isOwner || isApproved) {
Object.assign(passProps, post);
}
var toggleSticky = function toggleSticky() {
if (!isAdmin) {
throw new Error('Not authorized.');
}
setPost(_objectSpread(_objectSpread({}, post), {}, {
sticky: !post.sticky
}));
setPostSticky(!post.sticky);
};
var approve = function approve() {
if (!isAdmin) {
throw new Error('Not authorized.');
}
setPost(_objectSpread(_objectSpread({}, post), {}, {
approved: !post.approved
}));
approvePost();
};
var _deleteAnswer = function deleteAnswer(id) {
var _deleted$owner, _user10;
if (!answers.find(function (answer) {
return answer.id === id;
})) {
throw new Error('Answer not found');
}
var deleted = answers.find(function (answer) {
return answer.id === id;
});
var canDelete = (deleted === null || deleted === void 0 || (_deleted$owner = deleted.owner) === null || _deleted$owner === void 0 ? void 0 : _deleted$owner.id) === ((_user10 = user) === null || _user10 === void 0 ? void 0 : _user10.id) || isAdmin;
if (!canDelete) {
throw new Error('Not authorized to delete this answer');
}
setAnswers(answers.filter(function (answer) {
return answer.id !== id;
}).concat([_objectSpread(_objectSpread({}, deleted), {}, {
deleted: true
})]));
};
return (0, _jsxRuntime.jsxs)(_ServerSideProps.ServerSideProps, _objectSpread(_objectSpread({
id: id
}, passProps), {}, {
owner: {
id: (_post$owner7 = post.owner) === null || _post$owner7 === void 0 ? void 0 : _post$owner7.id,
name: (_post$owner8 = post.owner) === null || _post$owner8 === void 0 || (_post$owner8 = _post$owner8.strategies) === null || _post$owner8 === void 0 || (_post$owner8 = _post$owner8[(_user11 = user) === null || _user11 === void 0 ? void 0 : _user11.strategy]) === null || _post$owner8 === void 0 ? void 0 : _post$owner8.decoded.name,
picture: (_post$owner9 = post.owner) === null || _post$owner9 === void 0 || (_post$owner9 = _post$owner9.strategies) === null || _post$owner9 === void 0 || (_post$owner9 = _post$owner9[(_user12 = user) === null || _user12 === void 0 ? void 0 : _user12.strategy]) === null || _post$owner9 === void 0 ? void 0 : _post$owner9.decoded.picture,
email: (_post$owner10 = post.owner) === null || _post$owner10 === void 0 || (_post$owner10 = _post$owner10.strategies) === null || _post$owner10 === void 0 || (_post$owner10 = _post$owner10[(_user13 = user) === null || _user13 === void 0 ? void 0 : _user13.strategy]) === null || _post$owner10 === void 0 ? void 0 : _post$owner10.email
},
del: del,
deleted: post.deleted,
approve: approve,
toggleSticky: toggleSticky,
createAnswer: createAnswer,
canDelete:
// post?.owner?.id === user?.id ||
// Only admins can delete posts...
// TODO: add policies to toggle owner deletion
users.includes((_user14 = user) === null || _user14 === void 0 || (_user14 = _user14.strategies) === null || _user14 === void 0 || (_user14 = _user14[(_user15 = user) === null || _user15 === void 0 ? void 0 : _user15.strategy]) === null || _user14 === void 0 ? void 0 : _user14.email),
setBody: setBody
// TODO: Add renderWithoutEffects utility.
,
viewCounter: (0, _reactServer.render)((0, _jsxRuntime.jsx)(_ViewCounter.ViewCounter, {}, "post-".concat(id, "-view-counter")), {
clientProps: {},
initiator: _reactServer.Initiator.RenderServer,
context: null
}, null),
children: [(0, _jsxRuntime.jsx)(_Votings.Votings, {
policies: [_Votings.VotingPolicies.SingleVote]
}, "post-".concat(id, "-votings")), (0, _jsxRuntime.jsx)(_Reactions.Reactions, {
policies: [_Reactions.ReactionPolicies.SingleVote],
values: _Reactions.reactionsWhiteList
}, "post-".concat(id, "-reactions")), answers.filter(function (answer) {
var _answer$owner, _user16;
return !answer.deleted || ((_answer$owner = answer.owner) === null || _answer$owner === void 0 ? void 0 : _answer$owner.id) === ((_user16 = user) === null || _user16 === void 0 ? void 0 : _user16.id);
}).map(function (answer) {
return (0, _jsxRuntime.jsx)(Answer, _objectSpread(_objectSpread({}, answer), {}, {
deleteAnswer: function deleteAnswer() {
return _deleteAnswer(answer.id);
}
}), "answer-".concat(answer.id));
})]
}), "post-".concat(id, "-props"));
};
var ForumPolicies = exports.ForumPolicies = /*#__PURE__*/function (ForumPolicies) {
ForumPolicies["PostsNeedApproval"] = "PostsNeedApproval";
return ForumPolicies;
}({});
var Forum = exports.Forum = function Forum(_ref6, _ref7) {
var _context$headers2, _user26, _user27;
var id = _ref6.id,
name = _ref6.name,
policies = _ref6.policies,
users = _ref6.users;
var key = _ref7.key,
context = _ref7.context,
clientProps = _ref7.clientProps,
initiator = _ref7.initiator;
var user = null;
var clientId = (context === null || context === void 0 || (_context$headers2 = context.headers) === null || _context$headers2 === void 0 ? void 0 : _context$headers2['x-unique-id']) || 'server';
if ((0, _reactServer.isClientContext)(context)) try {
user = (0, _reactServer.authenticate)(context.headers, _config.JWT_SECRET);
} catch (e) {}
var _useState9 = (0, _reactServer.useState)([], {
key: 'posts',
scope: id
}),
_useState10 = (0, _slicedToArray2["default"])(_useState9, 2),
posts = _useState10[0],
setPosts = _useState10[1];
var createPost = function createPost(_ref8) {
var title = _ref8.title,
body = _ref8.body,
tags = _ref8.tags;
var post = {
id: (0, _uuid.v4)(),
title: title,
body: body,
tags: tags,
deleted: false,
approved: false,
owner: user || {
id: clientId
}
};
setPosts([].concat((0, _toConsumableArray2["default"])(posts), [post]));
return post;
};
var _deletePost = function deletePost(postId) {
var _owner$strategies, _user17, _user18, _user19, _user20, _user21;
var deleted = posts.find(function (post) {
return post.id === postId;
});
var _ref9 = deleted || {},
owner = _ref9.owner;
if ((owner === null || owner === void 0 || (_owner$strategies = owner.strategies) === null || _owner$strategies === void 0 || (_owner$strategies = _owner$strategies[(_user17 = user) === null || _user17 === void 0 ? void 0 : _user17.strategy]) === null || _owner$strategies === void 0 ? void 0 : _owner$strategies.email) !== ((_user18 = user) === null || _user18 === void 0 || (_user18 = _user18.strategies) === null || _user18 === void 0 || (_user18 = _user18[(_user19 = user) === null || _user19 === void 0 ? void 0 : _user19.strategy]) === null || _user18 === void 0 ? void 0 : _user18.email) && !users.includes((_user20 = user) === null || _user20 === void 0 || (_user20 = _user20.strategies) === null || _user20 === void 0 || (_user20 = _user20[(_user21 = user) === null || _user21 === void 0 ? void 0 : _user21.strategy]) === null || _user20 === void 0 ? void 0 : _user20.email)) {
throw new Error('Not an admin');
}
setPosts(posts.filter(function (post) {
return post.id !== postId;
}).concat([_objectSpread(_objectSpread({}, deleted), {}, {
deleted: true
})]));
return deleted;
};
var _approvePost = function approvePost(postId) {
var _user22, _user23;
var post = posts.find(function (p) {
return p.id === postId;
});
if (!post) {
throw new Error('Post not found');
}
if (!users.includes((_user22 = user) === null || _user22 === void 0 || (_user22 = _user22.strategies) === null || _user22 === void 0 || (_user22 = _user22[(_user23 = user) === null || _user23 === void 0 ? void 0 : _user23.strategy]) === null || _user22 === void 0 ? void 0 : _user22.email)) {
throw new Error('Not an admin');
}
var newPosts = [_objectSpread(_objectSpread({}, post), {}, {
approved: true
})].concat(posts.filter(function (p) {
return p.id !== postId;
}));
setPosts(newPosts);
};
var _setPostSticky = function setPostSticky(postId) {
var _user24, _user25;
var post = posts.find(function (p) {
return p.id === postId;
});
if (!post) {
throw new Error('Post not found');
}
if (!users.includes((_user24 = user) === null || _user24 === void 0 || (_user24 = _user24.strategies) === null || _user24 === void 0 || (_user24 = _user24[(_user25 = user) === null || _user25 === void 0 ? void 0 : _user25.strategy]) === null || _user24 === void 0 ? void 0 : _user24.email)) {
throw new Error('Not an admin');
}
var newPosts = [_objectSpread(_objectSpread({}, post), {}, {
sticky: true
})].concat(posts.filter(function (p) {
return p.id !== postId;
}));
setPosts(newPosts);
};
var isAdmin = users.includes((_user26 = user) === null || _user26 === void 0 || (_user26 = _user26.strategies) === null || _user26 === void 0 || (_user26 = _user26[(_user27 = user) === null || _user27 === void 0 ? void 0 : _user27.strategy]) === null || _user26 === void 0 ? void 0 : _user26.email);
/**
* When filtering posts for the client, you need to make sure they are still
* visible to the server. i.e. the server should be treated as admin.
* If you don't do this and a user tries to directly access a post the server won't find it
* as it's been filtered out.
*/
var filtered = posts.filter(function (post) {
return (0, _reactServer.isServerContext)(context) || isAdmin || !post.deleted;
}).filter(function (post) {
if (policies !== null && policies !== void 0 && policies.includes(ForumPolicies.PostsNeedApproval)) {
var _post$owner11, _user28;
return (0, _reactServer.isServerContext)(context) || post.approved || (post === null || post === void 0 || (_post$owner11 = post.owner) === null || _post$owner11 === void 0 ? void 0 : _post$owner11.id) === (((_user28 = user) === null || _user28 === void 0 ? void 0 : _user28.id) || clientId) || isAdmin;
}
return true;
});
var _ref10 = clientProps || {},
_ref10$page = _ref10.page,
page = _ref10$page === void 0 ? 1 : _ref10$page,
_ref10$pageSize = _ref10.pageSize,
pageSize = _ref10$pageSize === void 0 ? 25 : _ref10$pageSize,
_ref10$compound = _ref10.compound,
compound = _ref10$compound === void 0 ? false : _ref10$compound;
var start = !compound ? (page - 1) * pageSize : 0;
var end = page * pageSize;
return (0, _jsxRuntime.jsx)(_ServerSideProps.ServerSideProps, {
id: id,
name: name,
createPost: createPost,
deletePost: _deletePost,
totalCount: filtered.length,
page: page,
children: filtered.slice(start, end).map(function (post) {
return (0, _jsxRuntime.jsx)(Post, _objectSpread(_objectSpread({}, post), {}, {
deletePost: function deletePost() {
return _deletePost(post.id);
},
approvePost: function approvePost() {
return _approvePost(post.id);
},
setPostSticky: function setPostSticky() {
return _setPostSticky(post.id);
},
users: users
}), "post-".concat(post.id));
})
}, (0, _reactServer.clientKey)("forum-".concat(id, "-props"), context));
};
var Platform = exports.Platform = function Platform() {
var _useState11 = (0, _reactServer.useState)([], {
key: 'forums',
scope: 'platform'
}),
_useState12 = (0, _slicedToArray2["default"])(_useState11, 2),
forums = _useState12[0],
setForums = _useState12[1];
var createForum = function createForum(_ref11) {
var name = _ref11.name;
var forum = {
id: (0, _uuid.v4)(),
name: name
};
setForums([].concat((0, _toConsumableArray2["default"])(forums), [forum]));
};
return (0, _jsxRuntime.jsx)(_ServerSideProps.ServerSideProps, {
createForum: createForum,
children: forums.map(function (forum) {
return (0, _jsxRuntime.jsx)(Forum, _objectSpread({}, forum));
})
});
};