✨ Challenges
This commit is contained in:
		
							
								
								
									
										5
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | # Default ignored files | ||||||
|  | /shelf/ | ||||||
|  | /workspace.xml | ||||||
|  | # Editor-based HTTP Client requests | ||||||
|  | /httpRequests/ | ||||||
							
								
								
									
										12
									
								
								.idea/Fuxi.iml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								.idea/Fuxi.iml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <module type="WEB_MODULE" version="4"> | ||||||
|  |   <component name="NewModuleRootManager"> | ||||||
|  |     <content url="file://$MODULE_DIR$"> | ||||||
|  |       <excludeFolder url="file://$MODULE_DIR$/.tmp" /> | ||||||
|  |       <excludeFolder url="file://$MODULE_DIR$/temp" /> | ||||||
|  |       <excludeFolder url="file://$MODULE_DIR$/tmp" /> | ||||||
|  |     </content> | ||||||
|  |     <orderEntry type="inheritedJdk" /> | ||||||
|  |     <orderEntry type="sourceFolder" forTests="false" /> | ||||||
|  |   </component> | ||||||
|  | </module> | ||||||
							
								
								
									
										57
									
								
								.idea/codeStyles/Project.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								.idea/codeStyles/Project.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | <component name="ProjectCodeStyleConfiguration"> | ||||||
|  |   <code_scheme name="Project" version="173"> | ||||||
|  |     <HTMLCodeStyleSettings> | ||||||
|  |       <option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" /> | ||||||
|  |     </HTMLCodeStyleSettings> | ||||||
|  |     <JSCodeStyleSettings version="0"> | ||||||
|  |       <option name="FORCE_SEMICOLON_STYLE" value="true" /> | ||||||
|  |       <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" /> | ||||||
|  |       <option name="FORCE_QUOTE_STYlE" value="true" /> | ||||||
|  |       <option name="ENFORCE_TRAILING_COMMA" value="Remove" /> | ||||||
|  |       <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" /> | ||||||
|  |       <option name="SPACES_WITHIN_IMPORTS" value="true" /> | ||||||
|  |     </JSCodeStyleSettings> | ||||||
|  |     <TypeScriptCodeStyleSettings version="0"> | ||||||
|  |       <option name="FORCE_SEMICOLON_STYLE" value="true" /> | ||||||
|  |       <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" /> | ||||||
|  |       <option name="FORCE_QUOTE_STYlE" value="true" /> | ||||||
|  |       <option name="ENFORCE_TRAILING_COMMA" value="Remove" /> | ||||||
|  |       <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" /> | ||||||
|  |       <option name="SPACES_WITHIN_IMPORTS" value="true" /> | ||||||
|  |     </TypeScriptCodeStyleSettings> | ||||||
|  |     <VueCodeStyleSettings> | ||||||
|  |       <option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" /> | ||||||
|  |       <option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" /> | ||||||
|  |     </VueCodeStyleSettings> | ||||||
|  |     <codeStyleSettings language="HTML"> | ||||||
|  |       <option name="SOFT_MARGINS" value="120" /> | ||||||
|  |       <indentOptions> | ||||||
|  |         <option name="INDENT_SIZE" value="2" /> | ||||||
|  |         <option name="CONTINUATION_INDENT_SIZE" value="2" /> | ||||||
|  |         <option name="TAB_SIZE" value="2" /> | ||||||
|  |       </indentOptions> | ||||||
|  |     </codeStyleSettings> | ||||||
|  |     <codeStyleSettings language="JavaScript"> | ||||||
|  |       <option name="SOFT_MARGINS" value="120" /> | ||||||
|  |       <indentOptions> | ||||||
|  |         <option name="INDENT_SIZE" value="2" /> | ||||||
|  |         <option name="CONTINUATION_INDENT_SIZE" value="2" /> | ||||||
|  |         <option name="TAB_SIZE" value="2" /> | ||||||
|  |       </indentOptions> | ||||||
|  |     </codeStyleSettings> | ||||||
|  |     <codeStyleSettings language="TypeScript"> | ||||||
|  |       <option name="SOFT_MARGINS" value="120" /> | ||||||
|  |       <indentOptions> | ||||||
|  |         <option name="INDENT_SIZE" value="2" /> | ||||||
|  |         <option name="CONTINUATION_INDENT_SIZE" value="2" /> | ||||||
|  |         <option name="TAB_SIZE" value="2" /> | ||||||
|  |       </indentOptions> | ||||||
|  |     </codeStyleSettings> | ||||||
|  |     <codeStyleSettings language="Vue"> | ||||||
|  |       <option name="SOFT_MARGINS" value="120" /> | ||||||
|  |       <indentOptions> | ||||||
|  |         <option name="CONTINUATION_INDENT_SIZE" value="2" /> | ||||||
|  |       </indentOptions> | ||||||
|  |     </codeStyleSettings> | ||||||
|  |   </code_scheme> | ||||||
|  | </component> | ||||||
							
								
								
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | <component name="ProjectCodeStyleConfiguration"> | ||||||
|  |   <state> | ||||||
|  |     <option name="USE_PER_PROJECT_SETTINGS" value="true" /> | ||||||
|  |   </state> | ||||||
|  | </component> | ||||||
							
								
								
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project version="4"> | ||||||
|  |   <component name="ProjectModuleManager"> | ||||||
|  |     <modules> | ||||||
|  |       <module fileurl="file://$PROJECT_DIR$/.idea/Fuxi.iml" filepath="$PROJECT_DIR$/.idea/Fuxi.iml" /> | ||||||
|  |     </modules> | ||||||
|  |   </component> | ||||||
|  | </project> | ||||||
							
								
								
									
										7
									
								
								.idea/sqldialects.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.idea/sqldialects.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project version="4"> | ||||||
|  |   <component name="SqlDialectMappings"> | ||||||
|  |     <file url="file://$PROJECT_DIR$/supabase/migrations/20231210135930_challenges.sql" dialect="GenericSQL" /> | ||||||
|  |     <file url="PROJECT" dialect="PostgreSQL" /> | ||||||
|  |   </component> | ||||||
|  | </project> | ||||||
							
								
								
									
										6
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project version="4"> | ||||||
|  |   <component name="VcsDirectoryMappings"> | ||||||
|  |     <mapping directory="" vcs="Git" /> | ||||||
|  |   </component> | ||||||
|  | </project> | ||||||
| @@ -1,13 +1,15 @@ | |||||||
| <template> | <template> | ||||||
|   <n-message-provider> |   <n-message-provider> | ||||||
|  |     <n-dialog-provider> | ||||||
|       <nuxt-layout> |       <nuxt-layout> | ||||||
|         <nuxt-loading-indicator /> |         <nuxt-loading-indicator /> | ||||||
|         <nuxt-page /> |         <nuxt-page /> | ||||||
|       </nuxt-layout> |       </nuxt-layout> | ||||||
|  |     </n-dialog-provider> | ||||||
|   </n-message-provider> |   </n-message-provider> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { NMessageProvider } from "naive-ui"; | import { NMessageProvider, NDialogProvider } from "naive-ui"; | ||||||
| import "@/assets/css/index.css"; | import "@/assets/css/index.css"; | ||||||
| </script> | </script> | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										11
									
								
								application/components/problem/solution/program.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								application/components/problem/solution/program.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | <template> | ||||||
|  |  | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script setup lang="ts"> | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style scoped> | ||||||
|  |  | ||||||
|  | </style> | ||||||
| @@ -22,6 +22,7 @@ | |||||||
|     "vue-router": "^4.2.5" |     "vue-router": "^4.2.5" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|  |     "@guolao/vue-monaco-editor": "^1.4.1", | ||||||
|     "@ibm/plex": "^6.3.0", |     "@ibm/plex": "^6.3.0", | ||||||
|     "@nuxtjs/mdc": "^0.2.8", |     "@nuxtjs/mdc": "^0.2.8", | ||||||
|     "@supabase/supabase-js": "^2.39.0", |     "@supabase/supabase-js": "^2.39.0", | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								application/pages/about.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								application/pages/about.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="max-w-[720px] mx-auto"> | ||||||
|  |     <n-card> | ||||||
|  |       <brand-header /> | ||||||
|  |  | ||||||
|  |       <div>Get everyone interested in programming.</div> | ||||||
|  |  | ||||||
|  |       <n-divider class="mx-[-24px] w-[calc(100%+48px)]" /> | ||||||
|  |  | ||||||
|  |       <div class="text-gray text-xs"> | ||||||
|  |         <div> | ||||||
|  |           <nuxt-link class="link" target="_blank" to="https://smartsheep.studio">Made by SmartSheep Studio.</nuxt-link> | ||||||
|  |           Proprietary software. | ||||||
|  |         </div> | ||||||
|  |         <div>Fuxi Development Team © {{ new Date().getFullYear() }}</div> | ||||||
|  |       </div> | ||||||
|  |     </n-card> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { NCard, NDivider } from "naive-ui"; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style scoped> | ||||||
|  | .link { | ||||||
|  |   all: unset; | ||||||
|  |   cursor: pointer; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										116
									
								
								application/pages/challenges/[id].vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								application/pages/challenges/[id].vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="md:max-w-[720px] mx-auto"> | ||||||
|  |     <n-card segmented> | ||||||
|  |       <template #header> | ||||||
|  |         <n-page-header @back="navigateTo('/')"> | ||||||
|  |           <template #title>Challenge #{{ challenge?.id }}</template> | ||||||
|  |           <template #subtitle> | ||||||
|  |             <div class="flex items-center gap-2"> | ||||||
|  |               <n-tag size="small" class="case-capital">{{ challenge?.status?.replaceAll("-", " ") }}</n-tag> | ||||||
|  |             </div> | ||||||
|  |           </template> | ||||||
|  |         </n-page-header> | ||||||
|  |       </template> | ||||||
|  |  | ||||||
|  |       <client-only> | ||||||
|  |         <vue-monaco-editor | ||||||
|  |           :options="options" | ||||||
|  |           v-model:value="answer.code" | ||||||
|  |           class="min-h-[360px] code-editor" | ||||||
|  |         /> | ||||||
|  |       </client-only> | ||||||
|  |  | ||||||
|  |       <n-divider class="mx-[-24px] w-[calc(100%+48px)] divider-below-code" /> | ||||||
|  |  | ||||||
|  |       <template #action> | ||||||
|  |         <div class="w-full flex justify-between"> | ||||||
|  |           <div class="flex gap-2"> | ||||||
|  |             <n-button secondary circle class="rounded-[4px]" type="warning" :disabled="submitting" @click="save"> | ||||||
|  |               <template #icon> | ||||||
|  |                 <n-icon :component="Save" /> | ||||||
|  |               </template> | ||||||
|  |             </n-button> | ||||||
|  |           </div> | ||||||
|  |           <div class="flex gap-2"> | ||||||
|  |             <n-button secondary type="error" :disabled="submitting" @click="abandon">放弃</n-button> | ||||||
|  |             <n-button type="primary" :disabled="submitting" @click="submit">提交</n-button> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |     </n-card> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { NButton, NCard, NDivider, NPageHeader, NTag, NIcon, useDialog, useMessage } from "naive-ui"; | ||||||
|  | import { VueMonacoEditor } from "@guolao/vue-monaco-editor"; | ||||||
|  | import { Save } from "@vicons/carbon"; | ||||||
|  |  | ||||||
|  | const route = useRoute(); | ||||||
|  | const client = useSupabaseClient(); | ||||||
|  | const message = useMessage(); | ||||||
|  | const dialog = useDialog(); | ||||||
|  |  | ||||||
|  | const options = { | ||||||
|  |   minimap: { enabled: false } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const submitting = ref(false); | ||||||
|  |  | ||||||
|  | const { data: challenge } = await client | ||||||
|  |   .from("challenges") | ||||||
|  |   .select<any, any>("*") | ||||||
|  |   .eq("id", route.params.id) | ||||||
|  |   .single(); | ||||||
|  |  | ||||||
|  | useHead({ | ||||||
|  |   title: challenge ? `挑战 #${challenge.id}` : "挑战 #404" | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const answer = ref(challenge?.answer ?? {}); | ||||||
|  |  | ||||||
|  | async function save() { | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function abandon() { | ||||||
|  |   const instance = dialog.warning({ | ||||||
|  |     title: "警告", | ||||||
|  |     content: "你确定要放弃该次挑战?这会让该挑战立刻转化为放弃状态,并且扣除 5 点社会信用点,三思而后行!", | ||||||
|  |     positiveText: "确定", | ||||||
|  |     negativeText: "再试试", | ||||||
|  |     onPositiveClick: async () => { | ||||||
|  |       await client | ||||||
|  |         .from("challenges") | ||||||
|  |         // @ts-ignore | ||||||
|  |         .update<any>({ status: "abandoned" }) | ||||||
|  |         .eq("id", challenge.id); | ||||||
|  |  | ||||||
|  |       const delay = (ms: number) => new Promise(res => setTimeout(res, ms)); | ||||||
|  |  | ||||||
|  |       instance.loading = true | ||||||
|  |       message.info("已放弃挑战该题"); | ||||||
|  |  | ||||||
|  |       await delay(1850); | ||||||
|  |       window.close(); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function submit() { | ||||||
|  |  | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style scoped> | ||||||
|  | .code-editor { | ||||||
|  |   min-width: calc(100% + 48px); | ||||||
|  |   margin-top: -20px; | ||||||
|  |   margin-left: -24px; | ||||||
|  |   margin-right: -24px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .divider-below-code { | ||||||
|  |   margin-top: 0 !important; | ||||||
|  | } | ||||||
|  | </style> | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| <template> | <template> | ||||||
|   <div class="md:max-w-[720px] mx-auto"> |   <div class="md:max-w-[720px] mx-auto"> | ||||||
|     <problems-list /> |     <problem-list /> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|   | |||||||
| @@ -31,22 +31,90 @@ | |||||||
|         </div> |         </div> | ||||||
|         <n-empty v-else description="本题无公开样例" /> |         <n-empty v-else description="本题无公开样例" /> | ||||||
|       </section> |       </section> | ||||||
|  |  | ||||||
|  |       <template #action> | ||||||
|  |         <div class="w-full flex justify-end"> | ||||||
|  |           <n-button v-if="!answering" type="primary" :loading="submitting" @click="doChallenge">试答该题</n-button> | ||||||
|  |           <div v-else> | ||||||
|  |             <n-button type="primary" disabled> | ||||||
|  |               <template #icon> | ||||||
|  |                 <n-icon :component="Checkmark" /> | ||||||
|  |               </template> | ||||||
|  |               正在作答 | ||||||
|  |             </n-button> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|     </n-card> |     </n-card> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { NCard, NTag, NPageHeader, NDivider, NEmpty } from "naive-ui"; | import { NCard, NTag, NPageHeader, NDivider, NEmpty, NButton, NIcon, useMessage } from "naive-ui"; | ||||||
|  | import { Checkmark } from "@vicons/carbon"; | ||||||
| import "prismjs/themes/prism.css"; | import "prismjs/themes/prism.css"; | ||||||
| import "prismjs/prism"; | import "prismjs/prism"; | ||||||
|  |  | ||||||
|  | const user = useSupabaseUser(); | ||||||
| const client = useSupabaseClient(); | const client = useSupabaseClient(); | ||||||
|  | const message = useMessage(); | ||||||
| const route = useRoute(); | const route = useRoute(); | ||||||
|  |  | ||||||
| const { data: problem } = await client.from("problems").select<any, any>("*").eq("id", route.params.id).single(); | const submitting = ref(false); | ||||||
|  | const answering = ref(false); | ||||||
|  |  | ||||||
|  | const { data: problem } = await client | ||||||
|  |   .from("problems") | ||||||
|  |   .select<any, any>("*") | ||||||
|  |   .eq("id", route.params.id) | ||||||
|  |   .single(); | ||||||
| const { data: example } = await client | const { data: example } = await client | ||||||
|   .from("problem_cases") |   .from("problem_cases") | ||||||
|   .select<any, any>("*") |   .select<any, any>("*") | ||||||
|   .eq("problem", route.params.id) |   .eq("problem", route.params.id) | ||||||
|   .single(); |   .single(); | ||||||
|  |  | ||||||
|  | useHead({ | ||||||
|  |   title: problem?.title ?? "未知题目" | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | async function doChallenge() { | ||||||
|  |   if (problem == null) return; | ||||||
|  |  | ||||||
|  |   submitting.value = true; | ||||||
|  |  | ||||||
|  |   let { data } = await client | ||||||
|  |     .from("challenges") | ||||||
|  |     .select<any, any>("id") | ||||||
|  |     .eq("problem", problem?.id) | ||||||
|  |     .eq("status", "in-progress") | ||||||
|  |     .single(); | ||||||
|  |  | ||||||
|  |   if (data == null) { | ||||||
|  |     const res = await client | ||||||
|  |       .from("challenges") | ||||||
|  |       // @ts-ignore | ||||||
|  |       .insert<any>({ | ||||||
|  |         answers: {}, | ||||||
|  |         details: {}, | ||||||
|  |         status: "in-progress", | ||||||
|  |         problem: problem.id, | ||||||
|  |         author: user.value?.id | ||||||
|  |       }) | ||||||
|  |       .select<any, any>() | ||||||
|  |       .single(); | ||||||
|  |  | ||||||
|  |     if (res.error != null) { | ||||||
|  |       message.error(`Something went wrong... ${res.error.message}`); | ||||||
|  |       return; | ||||||
|  |     } else { | ||||||
|  |       data = res.data; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   submitting.value = false; | ||||||
|  |   answering.value = true; | ||||||
|  |   navigateTo(`/challenges/${data.id}`, { open: { target: "_blank" } }); | ||||||
|  |   setTimeout(() => answering.value = false, 3000); | ||||||
|  | } | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -1,14 +1,20 @@ | |||||||
| create table public.profiles ( | create table public.profiles | ||||||
|  | ( | ||||||
|     id       uuid not null references auth.users on delete cascade, |     id       uuid not null references auth.users on delete cascade, | ||||||
|     username varchar(64), |     username varchar(64), | ||||||
|     nickname varchar(256), |     nickname varchar(256), | ||||||
|     school   int8, |     school   int8, | ||||||
|     primary key (id) |     primary key (id) | ||||||
| ); | ); | ||||||
| alter table public.profiles enable row level security; |  | ||||||
|  | alter table public.profiles | ||||||
|  |     enable row level security; | ||||||
|  |  | ||||||
| create policy "Public profiles are viewable by everyone." on profiles for | create policy "Public profiles are viewable by everyone." on profiles for | ||||||
| select using (true); |     select using (true); | ||||||
|  |  | ||||||
| create policy "Users can insert their own profile." on profiles for | create policy "Users can insert their own profile." on profiles for | ||||||
| insert with check (auth.uid() = id); |     insert with check (auth.uid() = id); | ||||||
|  |  | ||||||
| create policy "Users can update own profile." on profiles for | create policy "Users can update own profile." on profiles for | ||||||
| update using (auth.uid() = id); |     update using (auth.uid() = id); | ||||||
| @@ -1,9 +1,10 @@ | |||||||
| create table public.problems ( | create table public.problems | ||||||
|  | ( | ||||||
|     id          bigint generated by default as identity, |     id          bigint generated by default as identity, | ||||||
|     title       text                     not null, |     title       text                     not null, | ||||||
|     description text                     not null, |     description text                     not null, | ||||||
|     type        character varying        not null, |     type        character varying        not null, | ||||||
|   tags character varying [] null, |     tags        character varying[]      null, | ||||||
|     author      uuid                     null, |     author      uuid                     null, | ||||||
|     metadata    jsonb                    null, |     metadata    jsonb                    null, | ||||||
|     is_draft    boolean                  null default true, |     is_draft    boolean                  null default true, | ||||||
| @@ -12,10 +13,15 @@ create table public.problems ( | |||||||
|     constraint problems_pkey primary key (id), |     constraint problems_pkey primary key (id), | ||||||
|     constraint problems_author_fkey foreign key (author) references auth.users (id) |     constraint problems_author_fkey foreign key (author) references auth.users (id) | ||||||
| ) tablespace pg_default; | ) tablespace pg_default; | ||||||
| alter table public.problems enable row level security; |  | ||||||
|  | alter table public.problems | ||||||
|  |     enable row level security; | ||||||
|  |  | ||||||
| create policy "Public problems are viewable by everyone." on problems for | create policy "Public problems are viewable by everyone." on problems for | ||||||
| select using (true); |     select using (true); | ||||||
| create table public.problem_cases ( |  | ||||||
|  | create table public.problem_cases | ||||||
|  | ( | ||||||
|     id          bigint generated by default as identity, |     id          bigint generated by default as identity, | ||||||
|     spec        jsonb not null, |     spec        jsonb not null, | ||||||
|     limitations jsonb not null, |     limitations jsonb not null, | ||||||
| @@ -25,6 +31,9 @@ create table public.problem_cases ( | |||||||
|     constraint problem_cases_pkey primary key (id), |     constraint problem_cases_pkey primary key (id), | ||||||
|     constraint problem_cases_author_fkey foreign key (problem) references public.problems (id) |     constraint problem_cases_author_fkey foreign key (problem) references public.problems (id) | ||||||
| ) tablespace pg_default; | ) tablespace pg_default; | ||||||
| alter table public.problem_cases enable row level security; |  | ||||||
|  | alter table public.problem_cases | ||||||
|  |     enable row level security; | ||||||
|  |  | ||||||
| create policy "Public problem cases are viewable by everyone." on problem_cases for | create policy "Public problem cases are viewable by everyone." on problem_cases for | ||||||
| select using (is_hidden = false); |     select using (is_hidden = false); | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| create table public.challenges ( | create table public.challenges | ||||||
|  | ( | ||||||
|     id         bigint generated by default as identity, |     id         bigint generated by default as identity, | ||||||
|     answers    jsonb        not null, |     answers    jsonb        not null, | ||||||
|     details    jsonb        not null, |     details    jsonb        not null, | ||||||
| @@ -10,5 +11,26 @@ create table public.challenges ( | |||||||
|     constraint challenges_author_fkey foreign key (author) references auth.users (id), |     constraint challenges_author_fkey foreign key (author) references auth.users (id), | ||||||
|     constraint challenges_problem_fkey foreign key (problem) references public.problems (id) |     constraint challenges_problem_fkey foreign key (problem) references public.problems (id) | ||||||
| ) tablespace pg_default; | ) tablespace pg_default; | ||||||
|  |  | ||||||
| alter table public.challenges enable row level security; | alter table public.challenges enable row level security; | ||||||
| create policy "The challagers can see their challenges" on "public"."challenges" for select to public using (auth.uid() = author) with check (true) |  | ||||||
|  | create | ||||||
|  | policy "Enable insert for everyone" on "public"."challenges" | ||||||
|  | as permissive for insert | ||||||
|  | to public | ||||||
|  | with check (true); | ||||||
|  |  | ||||||
|  | create | ||||||
|  | policy "Enable read access for users' own items" on "public"."challenges" | ||||||
|  | as permissive for | ||||||
|  | select | ||||||
|  |     to public | ||||||
|  |     using (author = auth.uid()); | ||||||
|  |  | ||||||
|  | create | ||||||
|  | policy "Enable update access for users' own items" on "public"."challenges" | ||||||
|  | as permissive for | ||||||
|  | update | ||||||
|  |     to public | ||||||
|  |     using (author = auth.uid()) | ||||||
|  | with check (author = auth.uid()) | ||||||
		Reference in New Issue
	
	Block a user