From 207ab63a52a9f29e0416c5220b874ef2cfdbe3a5 Mon Sep 17 00:00:00 2001 From: Not-A-Normal-Robot Date: Sat, 25 May 2024 23:33:57 +0700 Subject: [PATCH] work on database script --- js/background.js | 4 +- js/db.js | 172 +++++++++++++++++++++++++++++++++++++++++--- js/profile-setup.js | 149 +++++++++++--------------------------- 3 files changed, 207 insertions(+), 118 deletions(-) diff --git a/js/background.js b/js/background.js index ccefb86..6498743 100644 --- a/js/background.js +++ b/js/background.js @@ -42,8 +42,8 @@ width = bgCanvas?.offsetWidth; height = bgCanvas?.offsetHeight; - bgCanvas?.width = width; - bgCanvas?.height = height; + bgCanvas.width = width; + bgCanvas.height = height; let starCount = Math.floor(width * height * 6e-4) stars = new Array(starCount); diff --git a/js/db.js b/js/db.js index 7977de4..2e647a7 100644 --- a/js/db.js +++ b/js/db.js @@ -1,27 +1,35 @@ import { createClient } from 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js/+esm' export const SUPABASE_URL = "https://fohgyexhzptaxjqrrrfd.supabase.co"; export const SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZvaGd5ZXhoenB0YXhqcXJycmZkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDUwMjQxNTcsImV4cCI6MjAyMDYwMDE1N30.fa7XvwiBbWSe2MLIR6Wkh_OC95uV7UXxt7_25PlyAlc" -export const SUPABASE = createClient(SUPABASE_URL, SUPABASE_ANON_KEY); +export default SUPABASE = createClient(SUPABASE_URL, SUPABASE_ANON_KEY); window.SUPABASE = SUPABASE; +// #region Type definitions /** * @typedef {Object} User * @property {string} id - * @property {string} join_date * @property {string} username * @property {AccountState} account_state + * @property {Role} role + * @property {string} bio */ /** * @typedef {Object} Submission * @property {string} id * @property {string} game_mode - * @property {string} username - * @property {Object} score + * @property {Object | null} score * @property {string} upload_date - * @property {string} replay_date - * @property {string} replay_path + * @property {string?} replay_date * @property {string} submitted_by + * @property {SubmissionValidity} validity + * @property {string?} proof + */ + +/** + * @typedef {Object} ReplayData + * @property {string} submission_id + * @property {string} replay_data - Base64 encoded replay data */ /** @@ -29,7 +37,151 @@ window.SUPABASE = SUPABASE; * @enum {string} */ export const AccountState = { - NORMAL: "normal", - BANNED: "banned", - UNVERIFIED: "unverified" -} \ No newline at end of file + NORMAL: "Normal", + BANNED: "Banned", + UNVERIFIED: "Unverified" +} + +/** + * @readonly + * @enum {string} + */ +export const Role = { + USER: "User", + VERIFIER: "Verifier", + ADMIN: "Administrator" +} + +/** + * @readonly + * @enum {string} + */ +export const SubmissionValidity = { + UNVERIFIED: "Unverified", + VERIFIED: "Verified", + SUSPICIOUS: "Suspicious", + REJECTED: "Rejected" +} +// #endregion + +export const TABLES = { + PROFILES: "profiles", + SUBMISSIONS: "submissions", + REPLAYS: "replays", +} + +// #region Profile table functions +export async function getAllProfiles(limit = 10, offset = 0) { + const { data, error } = await SUPABASE.from(TABLES.PROFILES) + .select('*') + .range(offset, limit); + + if(error) throw new Error(error.message); + return data; +} +export async function getProfileById(id) { + const { data, error } = await SUPABASE.from(TABLES.PROFILES) + .select(1) + .eq('id', id); + + if(error) throw new Error(error.message); + return data[0]; +} +export async function getProfileByUsername(username) { + const { data, error } = await SUPABASE.from(TABLES.PROFILES) + .select(1) + .eq('username', username); + + if(error) throw new Error(error.message); + return data[0]; +} + +export async function editProfile(id, newProfileData) { + const { data, error } = await SUPABASE.from(TABLES.PROFILES) + .update(newProfileData) + .eq('id', id); + + if(error) throw new Error(error.message); + return data; +} +// #endregion + +// #region Submission table functions +export async function getSubmissionsByGameMode(gameMode, limit = 10, offset = 0) { + const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS) + .select('*') + .eq('game_mode', gameMode) + .range(offset, limit); + + if(error) throw new Error(error.message); + return data; +} +export async function getSubmissionById(id) { + const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS) + .select(1) + .eq('id', id); + + if(error) throw new Error(error.message); + return data[0]; +} +export async function getSubmissionByUserId(userId, limit = 10, offset = 0) { + const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS) + .select('*') + .eq('submitted_by', userId) + .range(offset, limit); + + if(error) throw new Error(error.message); + return data; +} + +export async function createSubmission(submissionData) { + const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS) + .insert(submissionData); + + if(error) throw new Error(error.message); + return data; +} +export async function editSubmission(id, newSubmissionData) { + const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS) + .update(newSubmissionData) + .eq('id', id); + + if(error) throw new Error(error.message); + return data; +} +export async function deleteSubmission(id) { + const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS) + .delete() + .eq('id', id); + + if(error) throw new Error(error.message); + return data; +} +// #endregion + +// #region Replay table functions +export async function getReplayDataBySubmissionId(submissionId) { + const { data, error } = await SUPABASE.from(TABLES.REPLAYS) + .select('*') + .eq('submission_id', submissionId); + + if(error) throw new Error(error.message); + return data[0]; +} + +export async function createReplayData(replayData) { + const { data, error } = await SUPABASE.from(TABLES.REPLAYS) + .insert(replayData); + + if(error) throw new Error(error.message); + return data; +} +export async function deleteReplayData(submissionId) { + const { data, error } = await SUPABASE.from(TABLES.REPLAYS) + .delete() + .eq('submission_id', submissionId); + + if(error) throw new Error(error.message); + return data; +} +// #endregion \ No newline at end of file diff --git a/js/profile-setup.js b/js/profile-setup.js index 26ebb8c..1554a23 100644 --- a/js/profile-setup.js +++ b/js/profile-setup.js @@ -1,117 +1,54 @@ import { SUPABASE } from "./db.js"; let NSFWJSInstance = null; - -{ // Counter for character count - for(const counter of document.getElementsByClassName('char-count')) { - const associatedId = counter.getAttribute('for'); - if(!associatedId) { - console.error('No associated input found for: ', counter); - continue; - } - - const associatedInput = document.getElementById(associatedId); - if(!associatedInput) { - console.error('No input found with id: ', associatedId); - continue; - } - - associatedInput.addEventListener('input', () => updateCounter(counter)); - updateCounter(counter); +{ + const ELEMENTS = { + form: document.getElementById('profile-setup'), + profileImageInput: document.getElementById('pfp-input'), + profileImagePreview: document.getElementById('pfp-preview'), + usernameInput: document.getElementById('username'), + bioInput: document.getElementById('bio'), + charCounters: document.getElementsByClassName('char-count'), } - function updateCounter(element) { - const associatedId = element.getAttribute('for'); - if(!associatedId) { - console.error('No associated input found for: ', element); - return; - } - - const associatedInput = document.getElementById(associatedId); - if(!associatedInput) { - console.error('No input found with id: ', associatedId); - return; - } + // #region Handle profile image preview + { + ELEMENTS.profileImageInput?.addEventListener('change', () => { + const file = profileImageInput.files[0]; + if(!file) return; - const maxChars = Number(associatedInput.getAttribute('maxlength') ?? Infinity); - const currentChars = associatedInput.value.length; - element.textContent = `${currentChars} / ${maxChars}`; + const reader = new FileReader(); + reader.onload = () => { + ELEMENTS.profileImagePreview.src = reader.result; + }; + reader.readAsDataURL(file); + }); } -} - -{ // Handle profile image upload - const profileImageInput = document.getElementById('pfp-input'); - profileImageInput?.addEventListener('change', () => { - const file = profileImageInput.files[0]; - if(!file) return; - - const reader = new FileReader(); - reader.onload = () => { - const image = document.getElementById('pfp-preview'); - if(image) { - image.src = reader.result; + // #endregion + + // #region Char counter + { + for(const counter of ELEMENTS.charCounters) { + const associatedId = counter.getAttribute('for'); + if(!associatedId) { + console.error('No associated input found for: ', counter); + continue; } - }; - reader.readAsDataURL(file); - }); -} - -{ // Handle NSFWJS - const MODEL_TYPE = "MobileNetV2"; - const INDEXEDDB_MODEL_KEY = "nsfwjs-model"; - async function loadNSFWJS() { - if(!("indexedDB" in window)) { - NSFWJSInstance = await nsfwjs.load(MODEL_TYPE); - return; - } - - if(await isModelCached()) { - const cachedInstance = await nsfwjs.load(`indexeddb://${INDEXEDDB_MODEL_KEY}`); - if(cachedInstance) { - NSFWJSInstance = cachedInstance; - return; + + const associatedInput = document.getElementById(associatedId); + if(!associatedInput) { + console.error('No input found with id: ', associatedId); + continue; } - } - const instance = await nsfwjs.load(MODEL_TYPE); - await instance.model.save(`indexeddb://${INDEXEDDB_MODEL_KEY}`); - - NSFWJSInstance = instance; - } - - async function isModelCached() { - return new Promise((resolve, reject) => { - const openRequest = indexedDB.open("tensorflowjs"); - - openRequest.onupgradeneeded = () => { - // The database did not previously exist, so it means the model is not saved - resolve(false); - }; - - openRequest.onsuccess = () => { - const db = openRequest.result; - const transaction = db.transaction("model_info_store", "readonly"); // tensorflow.js uses this object store name - const store = transaction.objectStore("model_info_store"); - const getRequest = store.get(INDEXEDDB_MODEL_KEY); - - getRequest.onsuccess = () => { - if (getRequest.result) { - resolve(true); - } else { - resolve(false); - } - }; - - getRequest.onerror = () => { - reject(getRequest.error); - }; - }; - - openRequest.onerror = () => { - reject(openRequest.error); - }; - }); + associatedInput.addEventListener('input', function() { + const maxChars = Number(associatedInput.getAttribute('maxlength') ?? Infinity); + const currentChars = associatedInput.value.length; + counter.textContent = `${currentChars} / ${maxChars}`; + }); + updateCounter(counter); + } } - - loadNSFWJS(); -} \ No newline at end of file + // #endregion +} +NSFWJSInstance = await nsfwjs.load("MobileNetV2"); \ No newline at end of file