Skip to content

Commit

Permalink
work on database script
Browse files Browse the repository at this point in the history
  • Loading branch information
Not-A-Normal-Robot committed May 25, 2024
1 parent 75c2bb6 commit 207ab63
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 118 deletions.
4 changes: 2 additions & 2 deletions js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
172 changes: 162 additions & 10 deletions js/db.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,187 @@
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
*/

/**
* @readonly
* @enum {string}
*/
export const AccountState = {
NORMAL: "normal",
BANNED: "banned",
UNVERIFIED: "unverified"
}
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
149 changes: 43 additions & 106 deletions js/profile-setup.js
Original file line number Diff line number Diff line change
@@ -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();
}
// #endregion
}
NSFWJSInstance = await nsfwjs.load("MobileNetV2");

0 comments on commit 207ab63

Please sign in to comment.