|
| 1 | +import { reddit } from '@devvit/web/server'; |
| 2 | +import type { Comment, Post } from '@devvit/web/server'; |
| 3 | +import type { T1, T3, T5 } from '@devvit/shared-types/tid.js'; |
| 4 | + |
| 5 | +export type NukeProps = { |
| 6 | + remove: boolean; |
| 7 | + lock: boolean; |
| 8 | + skipDistinguished: boolean; |
| 9 | + commentId: T1; |
| 10 | + subredditId: T5; |
| 11 | +}; |
| 12 | + |
| 13 | +export type NukePostProps = { |
| 14 | + remove: boolean; |
| 15 | + lock: boolean; |
| 16 | + skipDistinguished: boolean; |
| 17 | + postId: T3; |
| 18 | + subredditId: T5; |
| 19 | +}; |
| 20 | + |
| 21 | +const shouldIncludeComment = (comment: Comment, skipDistinguished: boolean) => |
| 22 | + !skipDistinguished || !comment.isDistinguished(); |
| 23 | + |
| 24 | +async function* getAllCommentsInThread( |
| 25 | + comment: Comment, |
| 26 | + skipDistinguished: boolean |
| 27 | +): AsyncGenerator<Comment> { |
| 28 | + if (shouldIncludeComment(comment, skipDistinguished)) { |
| 29 | + yield comment; |
| 30 | + } |
| 31 | + |
| 32 | + const replies = await comment.replies.all(); |
| 33 | + for (const reply of replies) { |
| 34 | + yield* getAllCommentsInThread(reply, skipDistinguished); |
| 35 | + } |
| 36 | +} |
| 37 | + |
| 38 | +async function* getAllCommentsInPost( |
| 39 | + post: Post, |
| 40 | + skipDistinguished: boolean |
| 41 | +): AsyncGenerator<Comment> { |
| 42 | + const comments = await post.comments.all(); |
| 43 | + for (const comment of comments) { |
| 44 | + yield* getAllCommentsInThread(comment, skipDistinguished); |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +export async function handleNukePost(props: NukePostProps) { |
| 49 | + const startTime = Date.now(); |
| 50 | + let success = true; |
| 51 | + let message: string; |
| 52 | + |
| 53 | + const shouldLock = props.lock; |
| 54 | + const shouldRemove = props.remove; |
| 55 | + const skipDistinguished = props.skipDistinguished; |
| 56 | + |
| 57 | + try { |
| 58 | + const [user, post] = await Promise.all([ |
| 59 | + reddit.getCurrentUser(), |
| 60 | + reddit.getPostById(props.postId), |
| 61 | + ]); |
| 62 | + |
| 63 | + if (!user) { |
| 64 | + return { success: false, message: "Can't get user" }; |
| 65 | + } |
| 66 | + |
| 67 | + const modPermissions = await user.getModPermissionsForSubreddit( |
| 68 | + post.subredditName |
| 69 | + ); |
| 70 | + const canManagePosts = |
| 71 | + modPermissions.includes('all') || modPermissions.includes('posts'); |
| 72 | + |
| 73 | + console.log( |
| 74 | + `Mod Info: r/${post.subredditName} u/${ |
| 75 | + user.username |
| 76 | + } permissions:${modPermissions}: ${ |
| 77 | + canManagePosts ? 'Can mod' : 'Cannot mod' |
| 78 | + }` |
| 79 | + ); |
| 80 | + |
| 81 | + if (!canManagePosts) { |
| 82 | + console.info( |
| 83 | + 'A user without the correct mod permissions tried to nuke all comments of a post.' |
| 84 | + ); |
| 85 | + return { |
| 86 | + message: 'You do not have the correct mod permissions to do this.', |
| 87 | + success: false, |
| 88 | + }; |
| 89 | + } |
| 90 | + |
| 91 | + const comments: Comment[] = []; |
| 92 | + for await (const eachComment of getAllCommentsInPost( |
| 93 | + post, |
| 94 | + skipDistinguished |
| 95 | + )) { |
| 96 | + comments.push(eachComment); |
| 97 | + } |
| 98 | + |
| 99 | + if (shouldLock) { |
| 100 | + await Promise.all( |
| 101 | + comments.map((comment) => comment.locked || comment.lock()) |
| 102 | + ); |
| 103 | + } |
| 104 | + |
| 105 | + if (shouldRemove) { |
| 106 | + await Promise.all( |
| 107 | + comments.map((comment) => comment.removed || comment.remove()) |
| 108 | + ); |
| 109 | + } |
| 110 | + |
| 111 | + const verbage = |
| 112 | + shouldLock && shouldRemove |
| 113 | + ? 'removed and locked' |
| 114 | + : shouldLock |
| 115 | + ? 'locked' |
| 116 | + : 'removed'; |
| 117 | + |
| 118 | + success = true; |
| 119 | + message = `Comments ${verbage}! Refresh the page to see the cleanup.`; |
| 120 | + const finishTime = Date.now(); |
| 121 | + const timeElapsed = (finishTime - startTime) / 1000; |
| 122 | + console.info( |
| 123 | + `${comments.length} comment(s) handled in ${timeElapsed} seconds.` |
| 124 | + ); |
| 125 | + } catch (err: unknown) { |
| 126 | + success = false; |
| 127 | + message = 'Mop failed! Please try again later.'; |
| 128 | + console.error(err); |
| 129 | + } |
| 130 | + |
| 131 | + return { success, message }; |
| 132 | +} |
| 133 | + |
| 134 | +export async function handleNuke(props: NukeProps) { |
| 135 | + const startTime = Date.now(); |
| 136 | + let success = true; |
| 137 | + let message: string; |
| 138 | + |
| 139 | + const shouldLock = props.lock; |
| 140 | + const shouldRemove = props.remove; |
| 141 | + const skipDistinguished = props.skipDistinguished; |
| 142 | + |
| 143 | + try { |
| 144 | + const comment = await reddit.getCommentById(props.commentId); |
| 145 | + const user = await reddit.getCurrentUser(); |
| 146 | + |
| 147 | + if (!user) { |
| 148 | + return { success: false, message: "Can't get user" }; |
| 149 | + } |
| 150 | + |
| 151 | + const modPermissions = await user.getModPermissionsForSubreddit( |
| 152 | + comment.subredditName |
| 153 | + ); |
| 154 | + const canManagePosts = |
| 155 | + modPermissions.includes('all') || modPermissions.includes('posts'); |
| 156 | + |
| 157 | + console.log( |
| 158 | + `Mod Info: r/${comment.subredditName} u/${ |
| 159 | + user.username |
| 160 | + } permissions:${modPermissions}: ${ |
| 161 | + canManagePosts ? 'Can mod' : 'Cannot mod' |
| 162 | + }` |
| 163 | + ); |
| 164 | + |
| 165 | + if (!canManagePosts) { |
| 166 | + console.info( |
| 167 | + 'A user without the correct mod permissions tried to comment mop.' |
| 168 | + ); |
| 169 | + return { |
| 170 | + message: 'You do not have the correct mod permissions to do this.', |
| 171 | + success: false, |
| 172 | + }; |
| 173 | + } |
| 174 | + |
| 175 | + const comments: Comment[] = []; |
| 176 | + for await (const eachComment of getAllCommentsInThread( |
| 177 | + comment, |
| 178 | + skipDistinguished |
| 179 | + )) { |
| 180 | + comments.push(eachComment); |
| 181 | + } |
| 182 | + |
| 183 | + if (shouldLock) { |
| 184 | + await Promise.all( |
| 185 | + comments.map((comment) => comment.locked || comment.lock()) |
| 186 | + ); |
| 187 | + } |
| 188 | + |
| 189 | + if (shouldRemove) { |
| 190 | + await Promise.all( |
| 191 | + comments.map((comment) => comment.removed || comment.remove()) |
| 192 | + ); |
| 193 | + } |
| 194 | + |
| 195 | + const verbage = |
| 196 | + shouldLock && shouldRemove |
| 197 | + ? 'removed and locked' |
| 198 | + : shouldLock |
| 199 | + ? 'locked' |
| 200 | + : 'removed'; |
| 201 | + |
| 202 | + success = true; |
| 203 | + message = `Comments ${verbage}! Refresh the page to see the cleanup.`; |
| 204 | + const finishTime = Date.now(); |
| 205 | + const timeElapsed = (finishTime - startTime) / 1000; |
| 206 | + console.info( |
| 207 | + `${comments.length} comment(s) handled in ${timeElapsed} seconds.` |
| 208 | + ); |
| 209 | + } catch (err: unknown) { |
| 210 | + success = false; |
| 211 | + message = 'Mop failed! Please try again later.'; |
| 212 | + console.error(err); |
| 213 | + } |
| 214 | + |
| 215 | + return { success, message }; |
| 216 | +} |
0 commit comments