From 78f60ee78a92a23cb87f8af687a0170f0b617088 Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Fri, 6 Oct 2023 16:33:29 +0100 Subject: [PATCH 01/42] issue #49: remove magnet uri from rss response --- api/src/controllers/rss.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/api/src/controllers/rss.js b/api/src/controllers/rss.js index 236062e..ad77fce 100644 --- a/api/src/controllers/rss.js +++ b/api/src/controllers/rss.js @@ -5,7 +5,6 @@ import { embellishTorrentsWithTrackerScrape } from "./torrent"; // prettier-ignore const getTorrentXml = (torrent, userId) => { - const announceUrl = `${process.env.SQ_BASE_URL}/sq/${userId}/announce` return ` ${torrent.name} ${torrent.description} @@ -14,11 +13,10 @@ const getTorrentXml = (torrent, userId) => { ${torrent.name} ${torrent.size} - magnet:?xt=urn:btih:${torrent.infoHash}&dn=${encodeURIComponent(torrent.name)}&tr=${encodeURIComponent(announceUrl)} - ${announceUrl} + ${process.env.SQ_BASE_URL}/sq/${userId}/announce From 4ca70467e35217b8a7ee5c90beb77db90f45674e Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Fri, 6 Oct 2023 16:37:41 +0100 Subject: [PATCH 02/42] issue #48: wrong category set on torrent edit --- client/pages/upload.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/client/pages/upload.js b/client/pages/upload.js index bd0dd8a..14a7b43 100644 --- a/client/pages/upload.js +++ b/client/pages/upload.js @@ -48,7 +48,7 @@ export const TorrentFields = ({ groupSuggestions, }) => { const [category, setCategory] = useState( - values?.type ?? slugify(Object.keys(categories)[0], { lower: true }) + values?.category ?? slugify(Object.keys(categories)[0], { lower: true }) ); const [sources, setSources] = useState([]); const [tags, setTags] = useState(values?.tags?.split(",") ?? []); @@ -340,9 +340,7 @@ const Upload = ({ token, userId }) => { {!!SQ_EXTENSION_BLACKLIST.length && ( - - {getLocaleString("uploadInfoBox1")} - + {getLocaleString("uploadInfoBox1")} { {torrentFile.name} ) : isDragActive ? ( - {getLocaleString("uploadDropFileHere")} + + {getLocaleString("uploadDropFileHere")} + ) : ( {getLocaleString("uploadDragDropClickSelect")} @@ -465,7 +465,10 @@ const Upload = ({ token, userId }) => { )} {SQ_ALLOW_ANONYMOUS_UPLOAD && ( - + )} - {total.toLocaleString()} {getLocaleString("torrResults")} — {getLocaleString("torrPage")} {page + 1} {getLocaleString("torrOf")}{" "} + {total.toLocaleString()} {getLocaleString("torrResults")} —{" "} + {getLocaleString("torrPage")} {page + 1} {getLocaleString("torrOf")}{" "} {(maxPage + 1).toLocaleString()} From 409c89d3327b6f92db39af7b601fa542e0af67b6 Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Fri, 6 Oct 2023 16:46:51 +0100 Subject: [PATCH 04/42] issue #38: enable sending of invites in open mode for admin users --- api/src/controllers/user.js | 2 +- client/pages/account.js | 107 +++++++++++++++++++++--------------- 2 files changed, 64 insertions(+), 45 deletions(-) diff --git a/api/src/controllers/user.js b/api/src/controllers/user.js index fed1be5..9491498 100644 --- a/api/src/controllers/user.js +++ b/api/src/controllers/user.js @@ -257,7 +257,7 @@ export const login = async (req, res, next) => { }; export const generateInvite = (mail) => async (req, res, next) => { - if (process.env.SQ_ALLOW_REGISTER !== "invite") { + if (process.env.SQ_ALLOW_REGISTER !== "invite" && req.userRole !== "admin") { res .status(403) .send("Can only send invites when tracker is in invite only mode"); diff --git a/client/pages/account.js b/client/pages/account.js index deb770e..e725081 100644 --- a/client/pages/account.js +++ b/client/pages/account.js @@ -62,7 +62,9 @@ const BuyItem = ({ text, cost, wallet, handleBuy }) => { disabled={unavailable || cannotAfford} mr={3} /> - + @@ -131,15 +133,14 @@ const Account = ({ token, invites = [], user, userRole }) => { return currentInvitesList; }); - addNotification("success", - `${getLocaleString("accInviteSentSuccess")}` - ); + addNotification("success", `${getLocaleString("accInviteSentSuccess")}`); setRemainingInvites((r) => r - 1); setShowInviteModal(false); } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("accCouldNotSendInvite")}: ${e.message}` ); console.error(e); @@ -174,9 +175,7 @@ const Account = ({ token, invites = [], user, userRole }) => { throw new Error(reason); } - addNotification("success", - `${getLocaleString("accPassChangedSuccess")}` - ); + addNotification("success", `${getLocaleString("accPassChangedSuccess")}`); const fields = e.target.querySelectorAll("input"); for (const field of fields) { @@ -184,7 +183,8 @@ const Account = ({ token, invites = [], user, userRole }) => { field.blur(); } } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("accCouldNotChangePass")}: ${e.message}` ); console.error(e); @@ -218,7 +218,8 @@ const Account = ({ token, invites = [], user, userRole }) => { throw new Error(reason); } - addNotification("success", + addNotification( + "success", `${getLocaleString("accItemsPurchasedSuccess")}` ); @@ -233,7 +234,8 @@ const Account = ({ token, invites = [], user, userRole }) => { field.blur(); } } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("accCouldNotBuyItems")}: ${e.message}` ); console.error(e); @@ -264,9 +266,7 @@ const Account = ({ token, invites = [], user, userRole }) => { setTotpBackupCodes(backupCodes); setTotpQrData(undefined); setTotpEnabled(true); - addNotification("success", - `${getLocaleString("acc2FAEnabled")}` - ); + addNotification("success", `${getLocaleString("acc2FAEnabled")}`); } else { const message = await enableRes.text(); addNotification("error", message); @@ -298,16 +298,15 @@ const Account = ({ token, invites = [], user, userRole }) => { if (disableRes.status === 200) { setTotpEnabled(false); - addNotification("success", - `${getLocaleString("acc2FADisabled")}` - ); + addNotification("success", `${getLocaleString("acc2FADisabled")}`); } else { const message = await disableRes.text(); addNotification("error", message); } } } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("accCouldNotToggle2FA")}: ${e.message}` ); console.error(e); @@ -337,7 +336,8 @@ const Account = ({ token, invites = [], user, userRole }) => { await router.push("/logout"); } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("accCouldNotDelAcc")}: ${e.message}` ); console.error(e); @@ -359,17 +359,29 @@ const Account = ({ token, invites = [], user, userRole }) => { {getLocaleString("accBonusPoints")} - {getLocaleString("accYouCurrentlyHave")} {bonusPoints} {getLocaleString("accBonusPointsHave")}. + {getLocaleString("accYouCurrentlyHave")} {bonusPoints}{" "} + {getLocaleString("accBonusPointsHave")}. - {getLocaleString("accYouWillEarn")} {SQ_BP_EARNED_PER_GB}{" "} - {pluralize(`${getLocaleString("accBonusPointsHave")}`, SQ_BP_EARNED_PER_GB)} {getLocaleString("accForEveryGBYouUpload")}. + {getLocaleString("accYouWillEarn")}{" "} + {SQ_BP_EARNED_PER_GB}{" "} + {pluralize( + `${getLocaleString("accBonusPointsHave")}`, + SQ_BP_EARNED_PER_GB + )}{" "} + {getLocaleString("accForEveryGBYouUpload")}. - {getLocaleString("accYouWillEarn")} {SQ_BP_EARNED_PER_FILLED_REQUEST}{" "} - {pluralize(`${getLocaleString("accBonusPointsHave")}`, SQ_BP_EARNED_PER_FILLED_REQUEST)} {getLocaleString("accEveryRequestYouFulfill")}{" "} - {SQ_BP_EARNED_PER_FILLED_REQUEST * 2} {getLocaleString("accIfYouAreAlsUploaderAcceptTorrent")}. + {getLocaleString("accYouWillEarn")}{" "} + {SQ_BP_EARNED_PER_FILLED_REQUEST}{" "} + {pluralize( + `${getLocaleString("accBonusPointsHave")}`, + SQ_BP_EARNED_PER_FILLED_REQUEST + )}{" "} + {getLocaleString("accEveryRequestYouFulfill")}{" "} + {SQ_BP_EARNED_PER_FILLED_REQUEST * 2}{" "} + {getLocaleString("accIfYouAreAlsUploaderAcceptTorrent")}. * + *": { mt: 3 } }} mb={5}> @@ -388,9 +400,8 @@ const Account = ({ token, invites = [], user, userRole }) => { handleBuy={(e) => handleBuy(e, "upload")} /> - {SQ_ALLOW_REGISTER === "invite" && ( + {(SQ_ALLOW_REGISTER === "invite" || userRole === "admin") && ( <> - {" "} { pl={4} > - {remainingInvites.toLocaleString()} {getLocaleString("accRemaining")} + {remainingInvites.toLocaleString()}{" "} + {getLocaleString("accRemaining")} + )} @@ -635,11 +650,15 @@ const Account = ({ token, invites = [], user, userRole }) => { )} {showInviteModal && ( setShowInviteModal(false)}> - - {getLocaleString("accInviteText1")} - + {getLocaleString("accInviteText1")} - + {userRole === "admin" && ( { > {getLocaleString("accCancel")} - + From 9538a6df540930be0398037024738e68001e2cee Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Fri, 6 Oct 2023 16:48:38 +0100 Subject: [PATCH 05/42] lint --- client/components/Comment.js | 4 +- client/pages/404.js | 1 - client/pages/_error.js | 4 +- client/pages/announcements/[slug]/edit.js | 7 +-- client/pages/announcements/index.js | 9 ++-- client/pages/announcements/new.js | 26 ++++++++--- client/pages/categories/index.js | 4 +- client/pages/index.js | 11 ++++- client/pages/reports/[id].js | 29 ++++++++---- client/pages/reports/index.js | 5 ++- client/pages/requests/[index].js | 44 +++++++++++------- client/pages/requests/index.js | 5 ++- client/pages/requests/new.js | 6 ++- client/pages/rss.js | 12 ++--- client/pages/search/[[...query]].js | 16 +++++-- client/pages/torrent/[infoHash].js | 4 +- client/pages/user/[username].js | 54 ++++++++++++++++++----- client/pages/verify-email.js | 4 +- client/pages/wiki/[[...slug]].js | 22 +++++---- client/pages/wiki/new.js | 11 +++-- 20 files changed, 187 insertions(+), 91 deletions(-) diff --git a/client/components/Comment.js b/client/components/Comment.js index d78fb81..690cf18 100644 --- a/client/components/Comment.js +++ b/client/components/Comment.js @@ -10,7 +10,6 @@ import Text from "./Text"; import LocaleContext from "../utils/LocaleContext"; const Comment = ({ comment }) => { - const { getLocaleString } = useContext(LocaleContext); return ( @@ -112,7 +111,8 @@ const Comment = ({ comment }) => { )} - {getLocaleString("reqPosted")} {moment(comment.created).format(`${getLocaleString("indexTime")}`)} + {getLocaleString("reqPosted")}{" "} + {moment(comment.created).format(`${getLocaleString("indexTime")}`)} {comment.comment} diff --git a/client/pages/404.js b/client/pages/404.js index 09edabd..b0d9982 100644 --- a/client/pages/404.js +++ b/client/pages/404.js @@ -5,7 +5,6 @@ import Text from "../components/Text"; import LocaleContext from "../utils/LocaleContext"; const NotFound = () => { - const { getLocaleString } = useContext(LocaleContext); return ( diff --git a/client/pages/_error.js b/client/pages/_error.js index f865bbf..043e98f 100644 --- a/client/pages/_error.js +++ b/client/pages/_error.js @@ -33,9 +33,7 @@ const ErrorPage = () => { {getLocaleString("errSomethingWentWrong")} :( {rateLimited ? ( - - {getLocaleString("errTooManyRequests")} - + {getLocaleString("errTooManyRequests")} ) : ( {getLocaleString("errIfErrorPersist")}{" "} diff --git a/client/pages/announcements/[slug]/edit.js b/client/pages/announcements/[slug]/edit.js index aeb4f35..c6f5fde 100644 --- a/client/pages/announcements/[slug]/edit.js +++ b/client/pages/announcements/[slug]/edit.js @@ -14,7 +14,6 @@ import MarkdownInput from "../../../components/MarkdownInput"; import LocaleContext from "../../../utils/LocaleContext"; const EditAnnouncement = ({ announcement, token, userRole }) => { - const { getLocaleString } = useContext(LocaleContext); if (userRole !== "admin") { @@ -58,14 +57,16 @@ const EditAnnouncement = ({ announcement, token, userRole }) => { throw new Error(reason); } - addNotification("success", + addNotification( + "success", `${getLocaleString("annAnnounceUpdatedSuccess")}` ); const slug = await updateAnnouncementRes.text(); router.push(`/announcements/${slug}`); } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("annCouldNotUpdateAnnounce")}: ${e.message}` ); console.error(e); diff --git a/client/pages/announcements/index.js b/client/pages/announcements/index.js index 4837d99..00ad65d 100644 --- a/client/pages/announcements/index.js +++ b/client/pages/announcements/index.js @@ -12,7 +12,6 @@ import List from "../../components/List"; import LocaleContext from "../../utils/LocaleContext"; const Announcements = ({ announcements, pinnedAnnouncements, userRole }) => { - const { getLocaleString } = useContext(LocaleContext); return ( @@ -61,7 +60,9 @@ const Announcements = ({ announcements, pinnedAnnouncements, userRole }) => { header: `${getLocaleString("accCreated")}`, accessor: "created", cell: ({ value }) => ( - {moment(value).format(`${getLocaleString("indexTime")}`)} + + {moment(value).format(`${getLocaleString("indexTime")}`)} + ), rightAlign: true, gridWidth: "175px", @@ -96,7 +97,9 @@ const Announcements = ({ announcements, pinnedAnnouncements, userRole }) => { header: `${getLocaleString("accCreated")}`, accessor: "created", cell: ({ value }) => ( - {moment(value).format(`${getLocaleString("indexTime")}`)} + + {moment(value).format(`${getLocaleString("indexTime")}`)} + ), rightAlign: true, gridWidth: "175px", diff --git a/client/pages/announcements/new.js b/client/pages/announcements/new.js index 2538fde..4a8c533 100644 --- a/client/pages/announcements/new.js +++ b/client/pages/announcements/new.js @@ -14,7 +14,6 @@ import MarkdownInput from "../../components/MarkdownInput"; import LocaleContext from "../../utils/LocaleContext"; const NewAnnouncement = ({ token, userRole }) => { - const { getLocaleString } = useContext(LocaleContext); if (userRole !== "admin") { @@ -58,14 +57,16 @@ const NewAnnouncement = ({ token, userRole }) => { throw new Error(reason); } - addNotification("success", + addNotification( + "success", `${getLocaleString("annAnnounceCreatSuccess")}` ); const slug = await createAnnouncementRes.text(); router.push(`/announcements/${slug}`); } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("annCouldNotCreateAnnounce")}: ${e.message}` ); console.error(e); @@ -81,7 +82,12 @@ const NewAnnouncement = ({ token, userRole }) => { {getLocaleString("annNewAnnounce")}
- + { mb={4} required /> - - + + diff --git a/client/pages/categories/index.js b/client/pages/categories/index.js index aa18c80..8cc733b 100644 --- a/client/pages/categories/index.js +++ b/client/pages/categories/index.js @@ -59,7 +59,9 @@ const Categories = ({ tags }) => { ))} ) : ( - {getLocaleString("catNoCategoryHaveBeenDefined")} + + {getLocaleString("catNoCategoryHaveBeenDefined")} + )} diff --git a/client/pages/index.js b/client/pages/index.js index 226d755..1c6ca16 100644 --- a/client/pages/index.js +++ b/client/pages/index.js @@ -120,7 +120,9 @@ const Index = ({ {getLocaleString("reqPosted")}{" "} - {moment(latestAnnouncement.created).format(`${getLocaleString("indexTime")}`)}{" "} + {moment(latestAnnouncement.created).format( + `${getLocaleString("indexTime")}` + )}{" "} {getLocaleString("reqBy")}{" "} {latestAnnouncement.createdBy?.username ? ( )} - + diff --git a/client/pages/reports/[id].js b/client/pages/reports/[id].js index 2e7f4fe..2d2e528 100644 --- a/client/pages/reports/[id].js +++ b/client/pages/reports/[id].js @@ -48,13 +48,12 @@ const Report = ({ report, token, userRole }) => { throw new Error(reason); } - addNotification("success", - `${getLocaleString("repRepMarkSolved")}` - ); + addNotification("success", `${getLocaleString("repRepMarkSolved")}`); router.push("/reports"); } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("repCouldNotResolveRep")}: ${e.message}` ); console.error(e); @@ -69,18 +68,28 @@ const Report = ({ report, token, userRole }) => { return ( <> - + - {getLocaleString("repRepOn")} “{report.torrent.name}” - + + {getLocaleString("repRepOn")} “{report.torrent.name}” + + - {getLocaleString("repRep")} {moment(report.created).format(`${getLocaleString("indexTime")}`)} {getLocaleString("reqBy")}{" "} + {getLocaleString("repRep")}{" "} + {moment(report.created).format(`${getLocaleString("indexTime")}`)}{" "} + {getLocaleString("reqBy")}{" "} {report.reportedBy.username} @@ -103,7 +112,9 @@ const Report = ({ report, token, userRole }) => { {report.torrent.infoHash} ), - [getLocaleString("accCreated")]: moment(report.torrent.created).format(`${getLocaleString("indexTime")}`), + [getLocaleString("accCreated")]: moment( + report.torrent.created + ).format(`${getLocaleString("indexTime")}`), }} /> { - const { getLocaleString } = useContext(LocaleContext); if (userRole !== "admin") { @@ -52,7 +51,9 @@ const Reports = ({ reports, userRole }) => { header: `${getLocaleString("accCreated")}`, accessor: "created", cell: ({ value }) => ( - {moment(value).format(`${getLocaleString("indexTime")}`)} + + {moment(value).format(`${getLocaleString("indexTime")}`)} + ), rightAlign: true, gridWidth: "175px", diff --git a/client/pages/requests/[index].js b/client/pages/requests/[index].js index 55776c6..dff6f47 100644 --- a/client/pages/requests/[index].js +++ b/client/pages/requests/[index].js @@ -65,13 +65,12 @@ const Request = ({ request, token, user }) => { throw new Error(reason); } - addNotification("success", - `${getLocaleString("reqRequestDelSuccess")}` - ); + addNotification("success", `${getLocaleString("reqRequestDelSuccess")}`); router.push("/requests"); } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("reqCouldNotDelReq")}: ${e.message}` ); console.error(e); @@ -105,9 +104,7 @@ const Request = ({ request, token, user }) => { throw new Error(reason); } - addNotification("success", - `${getLocaleString("reqCommentPostSuccess")}` - ); + addNotification("success", `${getLocaleString("reqCommentPostSuccess")}`); setComments((c) => { const newComment = { @@ -122,7 +119,8 @@ const Request = ({ request, token, user }) => { commentInputRef.current.value = ""; } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("reqCommentNotPost")}: ${e.message}` ); console.error(e); @@ -156,7 +154,8 @@ const Request = ({ request, token, user }) => { throw new Error(reason); } - addNotification("success", + addNotification( + "success", `${getLocaleString("reqSuggestionAddSuccess")}` ); @@ -165,7 +164,8 @@ const Request = ({ request, token, user }) => { setShowSuggestModal(false); } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("reqSuggestionNotAdded")}: ${e.message}` ); console.error(e); @@ -197,14 +197,16 @@ const Request = ({ request, token, user }) => { throw new Error(reason); } - addNotification("success", + addNotification( + "success", `${getLocaleString("reqSuggestionAcceptSuccess")}` ); const { torrent } = await acceptRes.json(); setFulfilledBy(torrent); } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("reqCouldNotAcceptSuggestion")}: ${e.message}` ); console.error(e); @@ -233,7 +235,9 @@ const Request = ({ request, token, user }) => { - {getLocaleString("reqPosted")} {moment(request.created).format(`${getLocaleString("indexTime")}`)} {getLocaleString("reqBy")}{" "} + {getLocaleString("reqPosted")}{" "} + {moment(request.created).format(`${getLocaleString("indexTime")}`)}{" "} + {getLocaleString("reqBy")}{" "} {request.createdBy?.username ? ( {request.createdBy.username} @@ -317,7 +321,9 @@ const Request = ({ request, token, user }) => { header: `${getLocaleString("userUploaded")}`, accessor: "created", cell: ({ value }) => ( - {moment(value).format(`${getLocaleString("indexTime")}`)} + + {moment(value).format(`${getLocaleString("indexTime")}`)} + ), gridWidth: "175px", rightAlign: true, @@ -345,7 +351,9 @@ const Request = ({ request, token, user }) => { ]} /> ) : ( - {getLocaleString("reqNoTorrentsHaveBeenSuggestedYet")} + + {getLocaleString("reqNoTorrentsHaveBeenSuggestedYet")} + )} @@ -379,7 +387,11 @@ const Request = ({ request, token, user }) => { setShowSuggestModal(false)}> {getLocaleString("reqEnterInfohashTorrentBelow")} - + {error ? ( - {getLocaleString("searchSearchError")}: {error} + + {getLocaleString("searchSearchError")}: {error} + ) : ( <> {query && ( diff --git a/client/pages/torrent/[infoHash].js b/client/pages/torrent/[infoHash].js index 4738336..d733e75 100644 --- a/client/pages/torrent/[infoHash].js +++ b/client/pages/torrent/[infoHash].js @@ -487,7 +487,9 @@ const Torrent = ({ token, torrent = {}, userId, userRole, uid, userStats }) => { addNotification( "success", `${getLocaleString("torrTorrent")} ${ - bookmarked ? getLocaleString("torrRemovedFrom") : getLocaleString("torrAddedTo") + bookmarked + ? getLocaleString("torrRemovedFrom") + : getLocaleString("torrAddedTo") } ${getLocaleString("navBookmarks")}` ); diff --git a/client/pages/user/[username].js b/client/pages/user/[username].js index f97c71a..25d0ef4 100644 --- a/client/pages/user/[username].js +++ b/client/pages/user/[username].js @@ -68,7 +68,11 @@ const User = ({ token, user, userRole }) => { addNotification( "success", - `${user.username} ${banned ? [getLocaleString("userUnbanned")] : [getLocaleString("userBanned")]} ${getLocaleString("userSuccessfully")}` + `${user.username} ${ + banned + ? [getLocaleString("userUnbanned")] + : [getLocaleString("userBanned")] + } ${getLocaleString("userSuccessfully")}` ); setBanned((b) => !b); @@ -76,7 +80,9 @@ const User = ({ token, user, userRole }) => { } catch (e) { addNotification( "error", - `${getLocaleString("userCouldNot")} ${banned ? [getLocaleString("userUnban")] : [getLocaleString("userBan")]} ${user.username}: ${e.message}` + `${getLocaleString("userCouldNot")} ${ + banned ? [getLocaleString("userUnban")] : [getLocaleString("userBan")] + } ${user.username}: ${e.message}` ); console.error(e); } @@ -101,7 +107,9 @@ const User = ({ token, user, userRole }) => { mb={3} > - {user.username} {getLocaleString("userProfile")} + + {user.username} {getLocaleString("userProfile")} + {user.role === "admin" && ( {getLocaleString("userAdmin")} @@ -122,12 +130,16 @@ const User = ({ token, user, userRole }) => { )} {userRole === "admin" && cookies.username !== user.username && ( )} - {getLocaleString("userUserSince")} {moment(user.created).format(`${getLocaleString("userUserSinceTime")}`)} + {getLocaleString("userUserSince")}{" "} + {moment(user.created).format(`${getLocaleString("userUserSinceTime")}`)} {userRole === "admin" && ( @@ -140,9 +152,16 @@ const User = ({ token, user, userRole }) => { {getLocaleString("userOnlyAdminsSee")}
    - {user.email &&
  • {getLocaleString("email")}: {user.email}
  • } + {user.email && ( +
  • + {getLocaleString("email")}: {user.email} +
  • + )} {typeof user.emailVerified === "boolean" && ( -
  • {getLocaleString("userEmailVerified")}: {user.emailVerified ? "yes" : "no"}
  • +
  • + {getLocaleString("userEmailVerified")}:{" "} + {user.emailVerified ? "yes" : "no"} +
  • )} {user.invitedBy && (
  • @@ -153,10 +172,15 @@ const User = ({ token, user, userRole }) => {
  • )} {typeof user.remainingInvites === "number" && ( -
  • {getLocaleString("userRemainingInvites")}: {user.remainingInvites}
  • +
  • + {getLocaleString("userRemainingInvites")}:{" "} + {user.remainingInvites} +
  • )} {typeof user.bonusPoints === "number" && ( -
  • {getLocaleString("accBonusPoints")}: {user.bonusPoints}
  • +
  • + {getLocaleString("accBonusPoints")}: {user.bonusPoints} +
  • )}
@@ -295,7 +319,11 @@ const User = ({ token, user, userRole }) => { {showBanModal && ( setShowBanModal(false)}> - {getLocaleString("userYouSureWant")} {banned ? [getLocaleString("userUnban")] : [getLocaleString("userBan")]} {getLocaleString("userThisUserQ")} + {getLocaleString("userYouSureWant")}{" "} + {banned + ? [getLocaleString("userUnban")] + : [getLocaleString("userBan")]}{" "} + {getLocaleString("userThisUserQ")} - + )} diff --git a/client/pages/verify-email.js b/client/pages/verify-email.js index fc5cb92..f87d23a 100644 --- a/client/pages/verify-email.js +++ b/client/pages/verify-email.js @@ -76,7 +76,9 @@ const VerifyEmail = () => { borderRadius={1} p={4} > - {getLocaleString("veCouldNotVerifyEmailAddress")} {tokenError} + + {getLocaleString("veCouldNotVerifyEmailAddress")} {tokenError} + )} diff --git a/client/pages/wiki/[[...slug]].js b/client/pages/wiki/[[...slug]].js index 885f72e..3fa65c6 100644 --- a/client/pages/wiki/[[...slug]].js +++ b/client/pages/wiki/[[...slug]].js @@ -59,15 +59,14 @@ const Wiki = ({ page, allPages, token, userRole, slug }) => { throw new Error(reason); } - addNotification("success", - `${getLocaleString("wikiPageDelSuccess")}` - ); + addNotification("success", `${getLocaleString("wikiPageDelSuccess")}`); setShowDeleteModal(false); await router.push("/wiki"); } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("wikiCouldNotDelPage")}: ${e.message}` ); console.error(e); @@ -104,16 +103,15 @@ const Wiki = ({ page, allPages, token, userRole, slug }) => { throw new Error(reason); } - addNotification("success", - `${getLocaleString("wikiPageUpdateSuccess")}` - ); + addNotification("success", `${getLocaleString("wikiPageUpdateSuccess")}`); if (form.get("slug") === page.slug) window.location.reload(); else window.location.href = "/wiki" + (page.slug === "/" ? "" : form.get("slug")); } catch (e) { - addNotification("error", + addNotification( + "error", `${getLocaleString("wikiCouldNotUpdatePage")}: ${e.message}` ); console.error(e); @@ -167,7 +165,9 @@ const Wiki = ({ page, allPages, token, userRole, slug }) => { {getLocaleString("wikiLastEdited")}{" "} - {moment(page.updated ?? page.created).format(`${getLocaleString("indexTime")}`)}{" "} + {moment(page.updated ?? page.created).format( + `${getLocaleString("indexTime")}` + )}{" "} {getLocaleString("reqBy")}{" "} {page.createdBy?.username ? ( @@ -250,9 +250,7 @@ const Wiki = ({ page, allPages, token, userRole, slug }) => { )} {showDeleteModal && ( setShowDeleteModal(false)}> - - {getLocaleString("wikiDelThisPageQ")} - + {getLocaleString("wikiDelThisPageQ")} @@ -650,7 +660,11 @@ const Account = ({ token, invites = [], user, userRole }) => { )} {showInviteModal && ( setShowInviteModal(false)}> - {getLocaleString("accInviteText1")} + + {getLocaleString( + SQ_DISABLE_EMAIL ? "accInviteText1NoEmail" : "accInviteText1" + )} + { > {getLocaleString("accCancel")} - + diff --git a/config.example.js b/config.example.js index ce2f57a..8fbd1e1 100644 --- a/config.example.js +++ b/config.example.js @@ -85,18 +85,26 @@ module.exports = { // The URL of your MongoDB server. Under the recommended setup, it should be `mongodb://sq_mongodb/sqtracker`. SQ_MONGO_URL: "mongodb://sq_mongodb/sqtracker", + // Disables sending of any emails and removes the need for an SMTP server. + // Fine for testing, not recommended in production as users will not be able to reset their passwords. + SQ_DISABLE_EMAIL: false, + // The email address that mail will be sent from. + // Not required if SQ_DISABLE_EMAIL=true. SQ_MAIL_FROM_ADDRESS: "mail@sqtracker.dev", // The hostname of your SMTP server. + // Not required if SQ_DISABLE_EMAIL=true. SQ_SMTP_HOST: "smtp.example.com", // The port of your SMTP server. + // Not required if SQ_DISABLE_EMAIL=true. SQ_SMTP_PORT: 587, // Whether to force SMTP TLS: if true the connection will use TLS when connecting to server. // If false (the default) then TLS is used if server supports the STARTTLS extension. // In most cases set this value to true if you are connecting to port 465. For port 587 or 25 keep it false. + // Not required if SQ_DISABLE_EMAIL=true. SQ_SMTP_SECURE: false, }, secrets: { @@ -111,9 +119,11 @@ module.exports = { SQ_ADMIN_EMAIL: "admin@example.com", // The username to authenticate with your SMTP server with. + // Not required if SQ_DISABLE_EMAIL=true. SQ_SMTP_USER: "smtp_username", // The password to authenticate with your SMTP server with. + // Not required if SQ_DISABLE_EMAIL=true. SQ_SMTP_PASS: "smtp_password", }, }; From 5e1e955508d2c4103050e403b2eb3a9942af57b9 Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Wed, 21 Feb 2024 13:47:48 +0000 Subject: [PATCH 41/42] update dockerfiles, add nginx config --- README.md | 2 ++ api/Dockerfile | 2 +- api/src/utils/validateConfig.js | 8 -------- client/Dockerfile | 2 +- docker-compose.dev.yml | 10 +++++++-- docker-compose.yml | 8 ++++++++ nginx.conf | 36 +++++++++++++++++++++++++++++++++ 7 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 nginx.conf diff --git a/README.md b/README.md index 7d33c8f..a49d947 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,8 @@ The sqtracker client service provides the modern, responsive web interface that The HTTP proxy allows the client, API, and BitTorrent tracker to all be accessible via a single endpoint. +Traefik is recommended and is configured by default. An Nginx config file is also provided for those that prefer it and the `docker-compose.yml` file contains an Nginx block that can be enabled. + ### Deploying with Docker compose The sqtracker platform is designed to be deployed via Docker. Once a configuration file is created, deploying is as simple as running `docker compose up -d` at the root of the project. diff --git a/api/Dockerfile b/api/Dockerfile index 9cd92df..1cfed1d 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine +FROM node:16 ENV NODE_ENV=production ENV SENTRY_DSN="https://9b9761216607428180ea3b32bd1c8e58@o140996.ingest.sentry.io/4504645996576768" LABEL org.opencontainers.image.source=https://github.com/tdjsnelling/sqtracker diff --git a/api/src/utils/validateConfig.js b/api/src/utils/validateConfig.js index 38cc5c1..554b4c3 100644 --- a/api/src/utils/validateConfig.js +++ b/api/src/utils/validateConfig.js @@ -1,12 +1,4 @@ import * as yup from "yup"; -import en from "@sqtracker/client/locales/en.json"; -import es from "@sqtracker/client/locales/es.json"; -import it from "@sqtracker/client/locales/it.json"; -import ru from "@sqtracker/client/locales/ru.json"; -import de from "@sqtracker/client/locales/de.json"; -import zh from "@sqtracker/client/locales/zh.json"; -import eo from "@sqtracker/client/locales/eo.json"; -import fr from "@sqtracker/client/locales/fr.json"; const httpRegex = /http(s)?:\/\/.*/; const mongoRegex = /mongodb:\/\/.*/; diff --git a/client/Dockerfile b/client/Dockerfile index 0b19958..d76cb29 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine AS builder +FROM node:16 AS builder ARG SENTRY_AUTH_TOKEN ENV NODE_ENV=production ENV SENTRY_ORG=tdjsnelling diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 8874d31..c676757 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -17,11 +17,17 @@ services: volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - ./traefik.yml:/config/traefik.yml +# nginx: +# image: "nginx:latest" +# container_name: "sq_nginx" +# restart: always +# ports: +# - "80:80" +# volumes: +# - ./nginx.conf:/etc/nginx/nginx.conf database: container_name: sq_mongodb image: mongo:6.0 - ports: - - "127.0.0.1:27017:27017" volumes: - ./data:/data/db api: diff --git a/docker-compose.yml b/docker-compose.yml index 245287d..ca4737a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,6 +23,14 @@ services: - "/var/run/docker.sock:/var/run/docker.sock:ro" - ./letsencrypt:/letsencrypt - ./traefik.yml:/config/traefik.yml +# nginx: +# image: "nginx:latest" +# container_name: "sq_nginx" +# restart: always +# ports: +# - "80:80" +# volumes: +# - ./nginx.conf:/etc/nginx/nginx.conf database: container_name: sq_mongodb image: mongo:6.0 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..b93617a --- /dev/null +++ b/nginx.conf @@ -0,0 +1,36 @@ +events {} + +http { + server { + listen 80; + resolver 127.0.0.11; + + location / { + proxy_pass http://sq_client:3000; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + } + + location /api/ { + rewrite /api/(.*) /$1 break; + proxy_pass http://sq_api:3001; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + } + + location /sq/ { + proxy_pass http://sq_api:3001; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + } + } +} From f8bced481d52e1c8c3dd4fccf458382f2d9651d1 Mon Sep 17 00:00:00 2001 From: Tom Snelling Date: Tue, 18 Jun 2024 13:53:02 +0100 Subject: [PATCH 42/42] include development URLs in config.example.js --- config.example.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.example.js b/config.example.js index 8fbd1e1..cd1e816 100644 --- a/config.example.js +++ b/config.example.js @@ -77,12 +77,15 @@ module.exports = { SQ_SITE_DEFAULT_LOCALE: "en", // The URL of your tracker site. + // For local development, this should be `http://127.0.0.1:3000`. SQ_BASE_URL: "https://sqtracker.dev", // The URL of your API. Under the recommended setup, it should be `${SQ_BASE_URL}/api`. + // For local development, this should be `http://127.0.0.1:3001`. SQ_API_URL: "https://sqtracker.dev/api", // The URL of your MongoDB server. Under the recommended setup, it should be `mongodb://sq_mongodb/sqtracker`. + // For local development, this should be `mongodb://127.0.0.1/sqtracker`. SQ_MONGO_URL: "mongodb://sq_mongodb/sqtracker", // Disables sending of any emails and removes the need for an SMTP server.