Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent comments and proposals submission when anchoring #1966

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/components/ProposalForm/ProposalForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import ModalMDGuide from "src/components/ModalMDGuide";
import DraftSaver from "./DraftSaver";
import { useProposalForm } from "./hooks";
import usePolicy from "src/hooks/api/usePolicy";
import { isAnchoring } from "src/helpers";
import {
PROPOSAL_TYPE_REGULAR,
PROPOSAL_TYPE_RFP,
Expand Down Expand Up @@ -262,6 +263,11 @@ const ProposalFormWrapper = ({
const handleSubmit = useCallback(
async (values, { resetForm, setSubmitting, setFieldError }) => {
try {
if (isAnchoring()) {
throw new Error(
"Submitting proposals is temporarily unavailable while a daily censorship resistance routine is in progress. Sorry for the inconvenience. This will be fixed soon. Check back in 10 minutes."
);
}
const { type, rfpLink, ...others } = values;
if (type === PROPOSAL_TYPE_RFP_SUBMISSION) {
const rfpWithVoteSummaries = (await onFetchProposalsBatchWithoutState(
Expand Down
11 changes: 3 additions & 8 deletions src/containers/Comments/Comment/CommentWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import CommentForm from "src/components/CommentForm/CommentFormLazy";
import Link from "src/components/Link";
import { useComment } from "../hooks";
import Comment from "./Comment";
import { handleCommentSubmission } from "../helpers";

const ContextLink = React.memo(({ parentid, recordToken, recordType }) => (
<Link
Expand Down Expand Up @@ -122,14 +123,8 @@ const CommentWrapper = ({
}, [showReplies]);

const handleSubmitComment = useCallback(
(comment) => {
return onSubmitComment({
comment,
token,
parentID: commentid
});
},
[token, commentid, onSubmitComment]
handleCommentSubmission(onSubmitComment, token, commentid),
[onSubmitComment, token, commentid]
);

const handleCommentSubmitted = useCallback(() => {
Expand Down
64 changes: 6 additions & 58 deletions src/containers/Comments/Comments.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
createSelectOptionFromSortOption,
commentSortOptions,
handleCommentCensoringInfo,
handleCommentSubmission,
NUMBER_OF_LIST_PLACEHOLDERS
} from "./helpers";
import useIdentity from "src/hooks/api/useIdentity";
Expand All @@ -36,10 +37,6 @@ import useLocalStorage from "src/hooks/utils/useLocalStorage";

const COMMENTS_LOGIN_MODAL_ID = "commentsLoginModal";

// Anchoring issue ref: see https://github.com/decred/politeiagui/issues/1941
const TEMP_ANCHORING_MINUTE = 58;
const ANCHORING_TIMEOUT_MS = 5 * 60 * 1000; // 5' in ms

const Comments = ({
numOfComments,
recordToken,
Expand Down Expand Up @@ -93,15 +90,10 @@ const Comments = ({
const paywallMissing = paywallEnabled && !isPaid;
const isSingleThread = !!threadParentID;

const handleSubmitComment = useCallback(
(comment) => {
return onSubmitComment({
comment,
token: recordToken,
parentID: 0
});
},
[recordToken, onSubmitComment]
const handleSubmitComment = handleCommentSubmission(
onSubmitComment,
recordToken,
0
);

const handleSetSortOption = useCallback(
Expand Down Expand Up @@ -213,42 +205,6 @@ const Comments = ({
((comments && !comments.find((c) => c.commentid === threadParentID)) ||
numOfComments === 0);

// Temporarily block comments due to git anchoring: See https://github.com/decred/politeiagui/issues/1941
const getTimeLeftToAnchor = () => {
const date = new Date();
const timeLeft =
TEMP_ANCHORING_MINUTE * 60000 -
date.getMinutes() * 60000 -
date.getSeconds() * 1000 -
date.getMilliseconds();
return timeLeft;
};

const [isAnchoring, setIsAchoring] = useState(getTimeLeftToAnchor() <= 0);
const handleToggleAnchoring = useCallback(() => {
setIsAchoring(!isAnchoring);
}, [setIsAchoring, isAnchoring]);

useEffect(
function anchoringModeListener() {
let timeout = null;
if (isAnchoring) {
timeout = setTimeout(handleToggleAnchoring, ANCHORING_TIMEOUT_MS);
}
return () => timeout && clearTimeout(timeout);
},
[isAnchoring, handleToggleAnchoring]
);
useEffect(
function commentsAllowedListener() {
let timeout = null;
if (!isAnchoring) {
timeout = setTimeout(handleToggleAnchoring, getTimeLeftToAnchor());
}
return () => timeout && clearTimeout(timeout);
},
[isAnchoring, handleToggleAnchoring]
);
return (
<>
<Card
Expand Down Expand Up @@ -278,21 +234,13 @@ const Comments = ({
</P>
</Message>
)}
{isAnchoring && (
<Message kind="blocked">
Commenting temporarily unavailable while an hourly censorship
resistance routine is in progress. Sorry for the
inconvenience. This will be fixed soon. Check back in 5
minutes.
</Message>
)}
{!readOnly && !!identityError && <IdentityMessageError />}
</Or>
{!isSingleThread && !readOnly && (
<CommentForm
persistKey={`commenting-on-${recordToken}`}
onSubmit={handleSubmitComment}
disableSubmit={!!identityError || paywallMissing || isAnchoring}
disableSubmit={!!identityError || paywallMissing}
/>
)}
</LoggedInContent>
Expand Down
16 changes: 16 additions & 0 deletions src/containers/Comments/helpers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import orderBy from "lodash/fp/orderBy";
import { isAnchoring } from "src/helpers";

export const NUMBER_OF_LIST_PLACEHOLDERS = 3;

Expand Down Expand Up @@ -63,3 +64,18 @@ export function handleCommentCensoringInfo(cb, ...args) {
cb(...args, reason);
};
}

export function handleCommentSubmission(cb, token, parentID = 0) {
return (comment) => {
if (isAnchoring()) {
throw new Error(
"Commenting temporarily unavailable while a daily censorship resistance routine is in progress. Sorry for the inconvenience. This will be fixed soon. Check back in 10 minutes."
);
}
return cb({
comment,
token,
parentID
});
};
}
26 changes: 26 additions & 0 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -447,3 +447,29 @@ export const fromUSDCentsToUSDUnits = (cents) =>
export const fromUSDUnitsToUSDCents = (units) => parseInt(units * 100, 10);

export const isEmpty = (obj) => Object.keys(obj).length === 0;

/** Pure function that given 2 UNIX timestamps returns the differnce between them in minutes */
export const getTimeDiffInMinutes = (d1, d2) => {
return (d1 - d2) / 60e3;
};

/** This is a temporary fix to prevent comments and proposals submissions during anchoring time */
/**
* @function isAnchoring
* @param {string} anchoringStartTime UTC time to prevent submissions in HH:MM format
* @param {number} anchoringDuration Duration in minutes
*/
export const isAnchoring = (
anchoringStartTime = "06:58",
anchoringDuration = 10
) => {
const targetDate = new Date();
const [startHour, startMinute] = anchoringStartTime.split(":");
targetDate.setUTCHours(startHour);
targetDate.setUTCMinutes(startMinute);
const timeDiffMinutes = getTimeDiffInMinutes(
new Date().getTime(),
targetDate.getTime()
);
return timeDiffMinutes >= 0 && timeDiffMinutes < anchoringDuration;
};
4 changes: 3 additions & 1 deletion src/pages/User/VerifyKey/VerifyKey.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ const VerifyKey = ({ location, history }) => {
const success = verifyUserKey && verifyUserKey.success;
const error = verifyUserKeyError;
const pushToHome = useCallback(() => history.push("/"), [history]);
const successButtonText = (isCMS ? "Ok, go to invoices" : "Ok, go to proposals");
const successButtonText = isCMS
? "Ok, go to invoices"
: "Ok, go to proposals";

return (
<SingleContentPage>
Expand Down
26 changes: 26 additions & 0 deletions src/tests/helpers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,29 @@ describe("test helpers functions", () => {
);
});
});

describe("test getTimeDiffInMinutes function", () => {
test("it should return 0 when d2 == d1", () => {
expect(help.getTimeDiffInMinutes(1591030381, 1591030381)).toEqual(0);
});

test("it should return positive when d1 > d2", () => {
expect(
help.getTimeDiffInMinutes(1591030521000, 1591030381000)
).toBeGreaterThan(0);
});

test("it should return negative when d1 < d2", () => {
expect(
help.getTimeDiffInMinutes(1591030381000, 1591030700000)
).toBeLessThan(0);
});

test("it should return correctly within the same hour", () => {
expect(help.getTimeDiffInMinutes(1591030200000, 1591029900000)).toEqual(5);
});

test("it should return correctly when the hour overflows", () => {
expect(help.getTimeDiffInMinutes(1591031100000, 1591030500000)).toEqual(10);
});
});