a fun bot for the hc slack
at v0.2.0 7.0 kB view raw
1import { slackApp, slackClient } from "../../../index"; 2import { db } from "../../../libs/db"; 3import { eq } from "drizzle-orm"; 4import { users as usersTable } from "../../../libs/schema"; 5import { 6 fetchRecentProjectKeys, 7 getHackatimeName, 8 HACKATIME_VERSIONS, 9 type HackatimeVersion, 10} from "../../../libs/hackatime"; 11import { deployToHackClubCDN } from "../../../libs/cdn"; 12 13export async function handleSettings( 14 triggerID: string, 15 user: string, 16 prefill = false, 17) { 18 let initialValues: { 19 project_name: string; 20 project_description: string; 21 repo_link: string | undefined; 22 demo_link: string | undefined; 23 hackatime_version: HackatimeVersion; 24 hackatime_keys: string[]; 25 } = { 26 project_name: "", 27 project_description: "", 28 repo_link: undefined, 29 demo_link: undefined, 30 hackatime_version: "v1", 31 hackatime_keys: [], 32 }; 33 34 if (prefill) { 35 try { 36 // Check if user already has a project in the database 37 const existingUser = ( 38 await db 39 .select() 40 .from(usersTable) 41 .where(eq(usersTable.id, user)) 42 )[0]; 43 44 if (existingUser) { 45 initialValues = { 46 project_name: existingUser.projectName, 47 project_description: existingUser.projectDescription, 48 repo_link: existingUser.repoLink || undefined, 49 demo_link: existingUser.demoLink || undefined, 50 hackatime_version: 51 existingUser.hackatimeVersion as HackatimeVersion, 52 hackatime_keys: existingUser.hackatimeKeys 53 ? JSON.parse(existingUser.hackatimeKeys) 54 : [], 55 }; 56 } 57 } catch (error) { 58 console.error("Error prefilling form:", error); 59 } 60 } 61 62 await slackClient.views.open({ 63 trigger_id: triggerID, 64 view: { 65 type: "modal", 66 title: { 67 type: "plain_text", 68 text: "Setup Project", 69 }, 70 submit: { 71 type: "plain_text", 72 text: "Submit", 73 }, 74 callback_id: "takes_setup_submit", 75 blocks: [ 76 { 77 type: "input", 78 block_id: "project_name", 79 label: { 80 type: "plain_text", 81 text: "Project Name", 82 }, 83 element: { 84 type: "plain_text_input", 85 action_id: "project_name_input", 86 initial_value: initialValues.project_name, 87 placeholder: { 88 type: "plain_text", 89 text: "Enter your project name", 90 }, 91 }, 92 }, 93 { 94 type: "input", 95 block_id: "project_description", 96 label: { 97 type: "plain_text", 98 text: "Project Description", 99 }, 100 element: { 101 type: "plain_text_input", 102 action_id: "project_description_input", 103 multiline: true, 104 initial_value: initialValues.project_description, 105 placeholder: { 106 type: "plain_text", 107 text: "Describe your project", 108 }, 109 }, 110 }, 111 { 112 type: "input", 113 block_id: "project_banner", 114 label: { 115 type: "plain_text", 116 text: `Banner Image${prefill ? " (this will replace your current banner)" : ""}`, 117 }, 118 element: { 119 type: "file_input", 120 action_id: "project_banner_input", 121 }, 122 optional: prefill, 123 }, 124 { 125 type: "input", 126 block_id: "repo_link", 127 optional: true, 128 label: { 129 type: "plain_text", 130 text: "Repository Link", 131 }, 132 element: { 133 type: "plain_text_input", 134 action_id: "repo_link_input", 135 initial_value: initialValues.repo_link, 136 placeholder: { 137 type: "plain_text", 138 text: "Optional: Add a link to your repository", 139 }, 140 }, 141 }, 142 { 143 type: "input", 144 block_id: "demo_link", 145 optional: true, 146 label: { 147 type: "plain_text", 148 text: "Demo Link", 149 }, 150 element: { 151 type: "plain_text_input", 152 action_id: "demo_link_input", 153 initial_value: initialValues.demo_link, 154 placeholder: { 155 type: "plain_text", 156 text: "Optional: Add a link to your demo", 157 }, 158 }, 159 }, 160 { 161 type: "input", 162 block_id: "hackatime_version", 163 label: { 164 type: "plain_text", 165 text: "Hackatime Version", 166 }, 167 element: { 168 type: "static_select", 169 action_id: "hackatime_version_input", 170 initial_option: { 171 text: { 172 type: "plain_text", 173 text: getHackatimeName( 174 initialValues.hackatime_version, 175 ), 176 }, 177 value: initialValues.hackatime_version, 178 }, 179 options: Object.values(HACKATIME_VERSIONS).map((v) => ({ 180 text: { 181 type: "plain_text", 182 text: v.name, 183 }, 184 value: v.id, 185 })), 186 }, 187 }, 188 { 189 type: "input", 190 block_id: "project_keys", 191 label: { 192 type: "plain_text", 193 text: "Project Keys", 194 }, 195 element: { 196 type: "multi_static_select", 197 action_id: "project_keys_input", 198 initial_options: 199 initialValues.hackatime_keys.length === 0 200 ? undefined 201 : initialValues.hackatime_keys.map((key) => ({ 202 text: { 203 type: "plain_text", 204 text: key, 205 }, 206 value: key, 207 })), 208 options: ( 209 await fetchRecentProjectKeys( 210 user, 211 10, 212 initialValues.hackatime_version as HackatimeVersion, 213 ) 214 ).map((key) => ({ 215 text: { 216 type: "plain_text", 217 text: key, 218 }, 219 value: key, 220 })), 221 }, 222 }, 223 ], 224 }, 225 }); 226} 227 228export async function setupSubmitListener() { 229 slackApp.view("takes_setup_submit", async ({ payload, context }) => { 230 if (payload.type !== "view_submission") return; 231 const values = payload.view.state.values; 232 const userId = payload.user.id; 233 234 const file = values.project_banner?.project_banner_input?.files?.[0] 235 ?.url_private_download as string; 236 237 const hackatimeKeys = JSON.stringify( 238 values.project_keys?.project_keys_input?.selected_options?.map( 239 (option) => option.value, 240 ) || [], 241 ); 242 243 try { 244 const projectBannerUrl = file 245 ? await deployToHackClubCDN([file]).then( 246 (res) => res.files[0]?.deployedUrl, 247 ) 248 : undefined; 249 250 const hackatimeVersion = values.hackatime_version 251 ?.hackatime_version_input?.selected_option 252 ?.value as HackatimeVersion; 253 254 await db 255 .insert(usersTable) 256 .values({ 257 id: userId, 258 projectName: values.project_name?.project_name_input?.value, 259 projectDescription: 260 values.project_description?.project_description_input 261 ?.value, 262 projectBannerUrl, 263 repoLink: values.repo_link?.repo_link_input?.value, 264 demoLink: values.demo_link?.demo_link_input?.value, 265 hackatimeVersion, 266 hackatimeKeys, 267 }) 268 .onConflictDoUpdate({ 269 target: usersTable.id, 270 set: { 271 projectName: 272 values.project_name?.project_name_input?.value, 273 projectDescription: 274 values.project_description 275 ?.project_description_input?.value, 276 projectBannerUrl, 277 repoLink: values.repo_link?.repo_link_input?.value, 278 demoLink: values.demo_link?.demo_link_input?.value, 279 hackatimeVersion, 280 hackatimeKeys, 281 }, 282 }); 283 } catch (error) { 284 console.error("Error processing file:", error); 285 throw error; 286 } 287 }); 288}