From 633a1b912534df2f1716d2e3e2cded07207d7f4a Mon Sep 17 00:00:00 2001 From: igoradamenko Date: Sun, 4 Feb 2018 18:07:20 +0200 Subject: [PATCH 1/6] add delete request to rest description --- remark.rest | 3 +++ 1 file changed, 3 insertions(+) diff --git a/remark.rest b/remark.rest index 72fd9132..be45b4be 100644 --- a/remark.rest +++ b/remark.rest @@ -55,3 +55,6 @@ GET {{host}}/api/v1/list?site=remark ### get config GET {{host}}/api/v1/config + +### delete comment by id +DELETE {{host}}/api/v1/admin/comment/3665976683?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/ From d287a1896951bf236ec7021ad00527cfc8c988a0 Mon Sep 17 00:00:00 2001 From: igoradamenko Date: Sun, 4 Feb 2018 23:41:54 +0200 Subject: [PATCH 2/6] add pin / unpin to api --- web/app/common/api.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/web/app/common/api.js b/web/app/common/api.js index 97b1b9a8..9871abcc 100644 --- a/web/app/common/api.js +++ b/web/app/common/api.js @@ -2,11 +2,13 @@ import { siteId, url } from './settings'; import fetcher from './fetcher' +/* common */ + export const find = ({ url }) => fetcher.get(`/find?url=${url}&sort=-score&format=tree`); export const getComment = ({ id }) => fetcher.get(`/id/${id}?url=${url}`); -export const getUser = () => fetcher.get('/user'); +export const vote = ({ id, url, value }) => fetcher.put(`/vote/${id}?url=${url}&vote=${value}`); export const send = ({ text, pid }) => fetcher.post('/comment', { text, @@ -17,12 +19,19 @@ export const send = ({ text, pid }) => fetcher.post('/comment', { ...(pid ? { pid } : {}), }); -export const vote = ({ id, url, value }) => fetcher.put(`/vote/${id}?url=${url}&vote=${value}`); +export const getUser = () => fetcher.get('/user'); + +/* admin */ +export const pin = ({ id, url }) => fetcher.put(`/admin/pin/${id}?url=${url}&pin=1`); + +export const unpin = ({ id, url }) => fetcher.get(`/admin/pin/${id}?url=${url}&pin=0`); export default { find, getComment, - send, + pin, + unpin, vote, + send, getUser, }; From 8ff6e8e58957cf59f49b8ed65530d3d8508566a5 Mon Sep 17 00:00:00 2001 From: igoradamenko Date: Sun, 4 Feb 2018 23:52:10 +0200 Subject: [PATCH 3/6] add support for pin to comment component --- .../comment/__action/comment__action.scss | 4 + .../_admin/comment__controls_view_admin.scss | 3 + .../comment/__controls/comment__controls.scss | 1 - .../comment/__reply/comment__reply.scss | 3 - .../comment/_pinned/comment_pinned.scss | 7 ++ web/app/components/comment/comment.jsx | 80 ++++++++++++++++--- web/app/components/comment/index.js | 7 +- 7 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 web/app/components/comment/__action/comment__action.scss create mode 100644 web/app/components/comment/__controls/_view/_admin/comment__controls_view_admin.scss delete mode 100644 web/app/components/comment/__reply/comment__reply.scss create mode 100644 web/app/components/comment/_pinned/comment_pinned.scss diff --git a/web/app/components/comment/__action/comment__action.scss b/web/app/components/comment/__action/comment__action.scss new file mode 100644 index 00000000..d9703a9c --- /dev/null +++ b/web/app/components/comment/__action/comment__action.scss @@ -0,0 +1,4 @@ +.comment__action { + margin-left: 8px; + cursor: pointer; +} diff --git a/web/app/components/comment/__controls/_view/_admin/comment__controls_view_admin.scss b/web/app/components/comment/__controls/_view/_admin/comment__controls_view_admin.scss new file mode 100644 index 00000000..75ada7bb --- /dev/null +++ b/web/app/components/comment/__controls/_view/_admin/comment__controls_view_admin.scss @@ -0,0 +1,3 @@ +.comment__controls_view_admin { + color: #ff4700; +} diff --git a/web/app/components/comment/__controls/comment__controls.scss b/web/app/components/comment/__controls/comment__controls.scss index ebd3eb42..bcccf357 100644 --- a/web/app/components/comment/__controls/comment__controls.scss +++ b/web/app/components/comment/__controls/comment__controls.scss @@ -1,6 +1,5 @@ .comment__controls { display: inline-block; - margin-left: 8px; color: #06c5c5; @media (hover: hover) { diff --git a/web/app/components/comment/__reply/comment__reply.scss b/web/app/components/comment/__reply/comment__reply.scss deleted file mode 100644 index 31696d41..00000000 --- a/web/app/components/comment/__reply/comment__reply.scss +++ /dev/null @@ -1,3 +0,0 @@ -.comment__reply { - cursor: pointer; -} diff --git a/web/app/components/comment/_pinned/comment_pinned.scss b/web/app/components/comment/_pinned/comment_pinned.scss new file mode 100644 index 00000000..f21be6bc --- /dev/null +++ b/web/app/components/comment/_pinned/comment_pinned.scss @@ -0,0 +1,7 @@ +.comment_pinned { + &, &.comment_view_admin { + .comment__username { + color: #FFD700; + } + } +} diff --git a/web/app/components/comment/comment.jsx b/web/app/components/comment/comment.jsx index b1159b7d..f87a990e 100644 --- a/web/app/components/comment/comment.jsx +++ b/web/app/components/comment/comment.jsx @@ -14,24 +14,29 @@ export default class Comment extends Component { isInputVisible: false, }; - this.updateScoreState(props); + this.updateState(props); this.decreaseScore = this.decreaseScore.bind(this); this.increaseScore = this.increaseScore.bind(this); this.onReplyClick = this.onReplyClick.bind(this); this.onReply = this.onReply.bind(this); + this.onPinClick = this.onPinClick.bind(this); + this.onUnpinClick = this.onUnpinClick.bind(this); + this.onBlockClick = this.onBlockClick.bind(this); + this.onDeleteClick = this.onDeleteClick.bind(this); } componentWillReceiveProps(nextProps) { - this.updateScoreState(nextProps); + this.updateState(nextProps); } - updateScoreState(props) { - const { score = 0, votes = [] } = props.data; + updateState(props) { + const { pin, score = 0, votes = [] } = props.data; const userId = store.get('user').id; this.setState({ score: score, + pinned: !!pin, scoreIncreased: userId in votes && votes[userId], scoreDecreased: userId in votes && !votes[userId], }); @@ -43,6 +48,34 @@ export default class Comment extends Component { this.setState({ isInputVisible: !isInputVisible }); } + onPinClick() { + const { id } = this.props.data; + + this.setState({ pinned: true }); + + api.pin({ id, url }).then(() => { + api.getComment({ id }).then(comment => store.replaceComment(comment)); + }); + } + + onUnpinClick() { + const { id } = this.props.data; + + this.setState({ pinned: false }); + + api.pin({ id, url }).then(() => { + api.getComment({ id }).then(comment => store.replaceComment(comment)); + }); + } + + onBlockClick() { + console.log('block'); + } + + onDeleteClick() { + console.log('delete'); + } + increaseScore() { const { score, scoreIncreased, scoreDecreased } = this.state; const { id } = this.props.data; @@ -82,8 +115,9 @@ export default class Comment extends Component { this.setState({ isInputVisible: false }); } - render(props, { score, scoreIncreased, scoreDecreased, isInputVisible }) { + render(props, { pinned, score, scoreIncreased, scoreDecreased, isInputVisible }) { const { data, mix, mods = {} } = props; + const isAdmin = store.get('user').admin; const time = new Date(data.time); // TODO: which format for datetime should we choose? @@ -100,9 +134,14 @@ export default class Comment extends Component { }, }; - return ( + const defaultMods = { + pinned, // TODO: add default view mod or don't? -
+ view: o.user.admin ? 'admin' : null, + }; + + return ( +
@@ -126,8 +165,31 @@ export default class Comment extends Component { {o.time} - reply - + reply + + + { + isAdmin && + ( + + + { + !pinned && ( + pin + ) + } + + { + pinned && ( + unpin + ) + } + + block + delete + + ) + }
diff --git a/web/app/components/comment/index.js b/web/app/components/comment/index.js index a3edfb37..81cfc497 100644 --- a/web/app/components/comment/index.js +++ b/web/app/components/comment/index.js @@ -2,12 +2,15 @@ export { default } from './comment'; require('./comment.scss'); +require('./__action/comment__action.scss'); require('./__avatar/comment__avatar.scss'); require('./__body/comment__body.scss'); + require('./__controls/comment__controls.scss'); +require('./__controls/_view/_admin/comment__controls_view_admin.scss'); + require('./__info/comment__info.scss'); require('./__input/comment__input.scss'); -require('./__reply/comment__reply.scss'); require('./__score/comment__score.scss'); require('./__score-sign/comment__score-sign.scss'); require('./__score-value/comment__score-value.scss'); @@ -22,4 +25,6 @@ require('./__vote/_type/_up/comment__vote_type_up.scss'); require('./_level/comment_level.scss'); +require('./_pinned/comment_pinned.scss'); + require('./_view/_admin/comment_view_admin.scss'); From fab35349c23891c156aa83d0d4573154937b9c5e Mon Sep 17 00:00:00 2001 From: igoradamenko Date: Mon, 5 Feb 2018 00:01:51 +0200 Subject: [PATCH 4/6] add block request to rest description --- remark.rest | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/remark.rest b/remark.rest index be45b4be..bc69368a 100644 --- a/remark.rest +++ b/remark.rest @@ -30,7 +30,7 @@ Content-Type: application/json } ### pin comment -PUT {{host}}/api/v1/admin/pin/3665976683?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/&pin=0 +PUT {{host}}/api/v1/admin/pin/3665976683?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/&pin=1 ### vote for comment PUT {{host}}/api/v1/vote/3665976683?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/&vote=1 @@ -56,5 +56,8 @@ GET {{host}}/api/v1/list?site=remark ### get config GET {{host}}/api/v1/config +### block user +PUT {{host}}/api/v1/admin/user/username?site=remark&block=1 + ### delete comment by id DELETE {{host}}/api/v1/admin/comment/3665976683?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/ From 35837ed6c9adeb088bb053eca24ff93feeab4a33 Mon Sep 17 00:00:00 2001 From: igoradamenko Date: Mon, 5 Feb 2018 00:26:48 +0200 Subject: [PATCH 5/6] add remove, blockUser and unblockUser to api --- web/app/common/api.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/web/app/common/api.js b/web/app/common/api.js index 9871abcc..1b84d372 100644 --- a/web/app/common/api.js +++ b/web/app/common/api.js @@ -24,14 +24,23 @@ export const getUser = () => fetcher.get('/user'); /* admin */ export const pin = ({ id, url }) => fetcher.put(`/admin/pin/${id}?url=${url}&pin=1`); -export const unpin = ({ id, url }) => fetcher.get(`/admin/pin/${id}?url=${url}&pin=0`); +export const unpin = ({ id, url }) => fetcher.put(`/admin/pin/${id}?url=${url}&pin=0`); + +export const remove = ({ id }) => fetcher.delete(`/admin/comment/${id}?url=${url}`); + +export const blockUser = ({ id }) => fetcher.put(`/admin/user/${id}?&block=1`); + +export const unblockUser = ({ id }) => fetcher.put(`/admin/user/${id}?&block=0`); export default { find, getComment, - pin, - unpin, vote, send, getUser, + pin, + unpin, + remove, + blockUser, + unblockUser, }; From 2f9146f4625df6dd4386ed813fb8c48ac33c3f5d Mon Sep 17 00:00:00 2001 From: igoradamenko Date: Mon, 5 Feb 2018 00:27:37 +0200 Subject: [PATCH 6/6] add handlers for block, unblock and remove in comment component --- .../comment/__controls/comment__controls.scss | 1 + web/app/components/comment/comment.jsx | 57 ++++++++++++++----- .../thread/_hidden/thread_hidden.scss | 3 + web/app/components/thread/index.js | 2 + web/app/components/thread/thread.jsx | 25 +++++++- 5 files changed, 72 insertions(+), 16 deletions(-) create mode 100644 web/app/components/thread/_hidden/thread_hidden.scss diff --git a/web/app/components/comment/__controls/comment__controls.scss b/web/app/components/comment/__controls/comment__controls.scss index bcccf357..0b0f164c 100644 --- a/web/app/components/comment/__controls/comment__controls.scss +++ b/web/app/components/comment/__controls/comment__controls.scss @@ -1,6 +1,7 @@ .comment__controls { display: inline-block; color: #06c5c5; + user-select: none; @media (hover: hover) { margin-left: 0; diff --git a/web/app/components/comment/comment.jsx b/web/app/components/comment/comment.jsx index f87a990e..5509a54c 100644 --- a/web/app/components/comment/comment.jsx +++ b/web/app/components/comment/comment.jsx @@ -23,6 +23,7 @@ export default class Comment extends Component { this.onPinClick = this.onPinClick.bind(this); this.onUnpinClick = this.onUnpinClick.bind(this); this.onBlockClick = this.onBlockClick.bind(this); + this.onUnblockClick = this.onUnblockClick.bind(this); this.onDeleteClick = this.onDeleteClick.bind(this); } @@ -37,6 +38,7 @@ export default class Comment extends Component { this.setState({ score: score, pinned: !!pin, + userBlocked: !!store.get('user').block, scoreIncreased: userId in votes && votes[userId], scoreDecreased: userId in votes && !votes[userId], }); @@ -69,11 +71,29 @@ export default class Comment extends Component { } onBlockClick() { - console.log('block'); + const { user: { id } } = this.props.data; + + this.setState({ userBlocked: true }); + + api.blockUser({ id }); + } + + onUnblockClick() { + const { user: { id } } = this.props.data; + + this.setState({ userBlocked: false }); + + api.unblockUser({ id }); } onDeleteClick() { - console.log('delete'); + const { id } = this.props.data; + + api.remove({ id }).then(() => { + if (this.props.onDelete) { + this.props.onDelete(); + } + }); } increaseScore() { @@ -115,7 +135,7 @@ export default class Comment extends Component { this.setState({ isInputVisible: false }); } - render(props, { pinned, score, scoreIncreased, scoreDecreased, isInputVisible }) { + render(props, { userBlocked, pinned, score, scoreIncreased, scoreDecreased, isInputVisible }) { const { data, mix, mods = {} } = props; const isAdmin = store.get('user').admin; @@ -150,17 +170,17 @@ export default class Comment extends Component { {o.user.name} - vote up + vote up {o.score.sign} {o.score.value} - vote down - + vote down + {o.time} @@ -185,7 +205,18 @@ export default class Comment extends Component { ) } - block + { + userBlocked && ( + unblock + ) + } + + { + !userBlocked && ( + block + ) + } + delete ) diff --git a/web/app/components/thread/_hidden/thread_hidden.scss b/web/app/components/thread/_hidden/thread_hidden.scss new file mode 100644 index 00000000..ce7eb403 --- /dev/null +++ b/web/app/components/thread/_hidden/thread_hidden.scss @@ -0,0 +1,3 @@ +.thread_hidden { + display: none; +} diff --git a/web/app/components/thread/index.js b/web/app/components/thread/index.js index c774686b..b995c833 100644 --- a/web/app/components/thread/index.js +++ b/web/app/components/thread/index.js @@ -1,3 +1,5 @@ export { default } from './thread'; require('./thread.scss'); + +require('./_hidden/thread_hidden.scss'); diff --git a/web/app/components/thread/thread.jsx b/web/app/components/thread/thread.jsx index f7b0d5e6..2910ab19 100644 --- a/web/app/components/thread/thread.jsx +++ b/web/app/components/thread/thread.jsx @@ -3,12 +3,31 @@ import { h, Component } from 'preact'; import Comment from 'components/comment'; export default class Thread extends Component { - render(props, state) { + constructor(props) { + super(props); + + this.state = { + hidden: false, + }; + + this.hide = this.hide.bind(this); + } + + hide() { + this.setState({ hidden: true }); + } + + render(props, { hidden }) { const { data: { comment, replies = [] }, mix, mods = {} } = props; return ( -
- +