Skip to content

Commit 207ab63

Browse files
work on database script
1 parent 75c2bb6 commit 207ab63

File tree

3 files changed

+207
-118
lines changed

3 files changed

+207
-118
lines changed

js/background.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
width = bgCanvas?.offsetWidth;
4343
height = bgCanvas?.offsetHeight;
4444

45-
bgCanvas?.width = width;
46-
bgCanvas?.height = height;
45+
bgCanvas.width = width;
46+
bgCanvas.height = height;
4747

4848
let starCount = Math.floor(width * height * 6e-4)
4949
stars = new Array(starCount);

js/db.js

Lines changed: 162 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,187 @@
11
import { createClient } from 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js/+esm'
22
export const SUPABASE_URL = "https://fohgyexhzptaxjqrrrfd.supabase.co";
33
export const SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZvaGd5ZXhoenB0YXhqcXJycmZkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDUwMjQxNTcsImV4cCI6MjAyMDYwMDE1N30.fa7XvwiBbWSe2MLIR6Wkh_OC95uV7UXxt7_25PlyAlc"
4-
export const SUPABASE = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
4+
export default SUPABASE = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
55
window.SUPABASE = SUPABASE;
66

7+
// #region Type definitions
78
/**
89
* @typedef {Object} User
910
* @property {string} id
10-
* @property {string} join_date
1111
* @property {string} username
1212
* @property {AccountState} account_state
13+
* @property {Role} role
14+
* @property {string} bio
1315
*/
1416

1517
/**
1618
* @typedef {Object} Submission
1719
* @property {string} id
1820
* @property {string} game_mode
19-
* @property {string} username
20-
* @property {Object} score
21+
* @property {Object | null} score
2122
* @property {string} upload_date
22-
* @property {string} replay_date
23-
* @property {string} replay_path
23+
* @property {string?} replay_date
2424
* @property {string} submitted_by
25+
* @property {SubmissionValidity} validity
26+
* @property {string?} proof
27+
*/
28+
29+
/**
30+
* @typedef {Object} ReplayData
31+
* @property {string} submission_id
32+
* @property {string} replay_data - Base64 encoded replay data
2533
*/
2634

2735
/**
2836
* @readonly
2937
* @enum {string}
3038
*/
3139
export const AccountState = {
32-
NORMAL: "normal",
33-
BANNED: "banned",
34-
UNVERIFIED: "unverified"
35-
}
40+
NORMAL: "Normal",
41+
BANNED: "Banned",
42+
UNVERIFIED: "Unverified"
43+
}
44+
45+
/**
46+
* @readonly
47+
* @enum {string}
48+
*/
49+
export const Role = {
50+
USER: "User",
51+
VERIFIER: "Verifier",
52+
ADMIN: "Administrator"
53+
}
54+
55+
/**
56+
* @readonly
57+
* @enum {string}
58+
*/
59+
export const SubmissionValidity = {
60+
UNVERIFIED: "Unverified",
61+
VERIFIED: "Verified",
62+
SUSPICIOUS: "Suspicious",
63+
REJECTED: "Rejected"
64+
}
65+
// #endregion
66+
67+
export const TABLES = {
68+
PROFILES: "profiles",
69+
SUBMISSIONS: "submissions",
70+
REPLAYS: "replays",
71+
}
72+
73+
// #region Profile table functions
74+
export async function getAllProfiles(limit = 10, offset = 0) {
75+
const { data, error } = await SUPABASE.from(TABLES.PROFILES)
76+
.select('*')
77+
.range(offset, limit);
78+
79+
if(error) throw new Error(error.message);
80+
return data;
81+
}
82+
export async function getProfileById(id) {
83+
const { data, error } = await SUPABASE.from(TABLES.PROFILES)
84+
.select(1)
85+
.eq('id', id);
86+
87+
if(error) throw new Error(error.message);
88+
return data[0];
89+
}
90+
export async function getProfileByUsername(username) {
91+
const { data, error } = await SUPABASE.from(TABLES.PROFILES)
92+
.select(1)
93+
.eq('username', username);
94+
95+
if(error) throw new Error(error.message);
96+
return data[0];
97+
}
98+
99+
export async function editProfile(id, newProfileData) {
100+
const { data, error } = await SUPABASE.from(TABLES.PROFILES)
101+
.update(newProfileData)
102+
.eq('id', id);
103+
104+
if(error) throw new Error(error.message);
105+
return data;
106+
}
107+
// #endregion
108+
109+
// #region Submission table functions
110+
export async function getSubmissionsByGameMode(gameMode, limit = 10, offset = 0) {
111+
const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS)
112+
.select('*')
113+
.eq('game_mode', gameMode)
114+
.range(offset, limit);
115+
116+
if(error) throw new Error(error.message);
117+
return data;
118+
}
119+
export async function getSubmissionById(id) {
120+
const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS)
121+
.select(1)
122+
.eq('id', id);
123+
124+
if(error) throw new Error(error.message);
125+
return data[0];
126+
}
127+
export async function getSubmissionByUserId(userId, limit = 10, offset = 0) {
128+
const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS)
129+
.select('*')
130+
.eq('submitted_by', userId)
131+
.range(offset, limit);
132+
133+
if(error) throw new Error(error.message);
134+
return data;
135+
}
136+
137+
export async function createSubmission(submissionData) {
138+
const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS)
139+
.insert(submissionData);
140+
141+
if(error) throw new Error(error.message);
142+
return data;
143+
}
144+
export async function editSubmission(id, newSubmissionData) {
145+
const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS)
146+
.update(newSubmissionData)
147+
.eq('id', id);
148+
149+
if(error) throw new Error(error.message);
150+
return data;
151+
}
152+
export async function deleteSubmission(id) {
153+
const { data, error } = await SUPABASE.from(TABLES.SUBMISSIONS)
154+
.delete()
155+
.eq('id', id);
156+
157+
if(error) throw new Error(error.message);
158+
return data;
159+
}
160+
// #endregion
161+
162+
// #region Replay table functions
163+
export async function getReplayDataBySubmissionId(submissionId) {
164+
const { data, error } = await SUPABASE.from(TABLES.REPLAYS)
165+
.select('*')
166+
.eq('submission_id', submissionId);
167+
168+
if(error) throw new Error(error.message);
169+
return data[0];
170+
}
171+
172+
export async function createReplayData(replayData) {
173+
const { data, error } = await SUPABASE.from(TABLES.REPLAYS)
174+
.insert(replayData);
175+
176+
if(error) throw new Error(error.message);
177+
return data;
178+
}
179+
export async function deleteReplayData(submissionId) {
180+
const { data, error } = await SUPABASE.from(TABLES.REPLAYS)
181+
.delete()
182+
.eq('submission_id', submissionId);
183+
184+
if(error) throw new Error(error.message);
185+
return data;
186+
}
187+
// #endregion

js/profile-setup.js

Lines changed: 43 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,54 @@
11
import { SUPABASE } from "./db.js";
22

33
let NSFWJSInstance = null;
4-
5-
{ // Counter for character count
6-
for(const counter of document.getElementsByClassName('char-count')) {
7-
const associatedId = counter.getAttribute('for');
8-
if(!associatedId) {
9-
console.error('No associated input found for: ', counter);
10-
continue;
11-
}
12-
13-
const associatedInput = document.getElementById(associatedId);
14-
if(!associatedInput) {
15-
console.error('No input found with id: ', associatedId);
16-
continue;
17-
}
18-
19-
associatedInput.addEventListener('input', () => updateCounter(counter));
20-
updateCounter(counter);
4+
{
5+
const ELEMENTS = {
6+
form: document.getElementById('profile-setup'),
7+
profileImageInput: document.getElementById('pfp-input'),
8+
profileImagePreview: document.getElementById('pfp-preview'),
9+
usernameInput: document.getElementById('username'),
10+
bioInput: document.getElementById('bio'),
11+
charCounters: document.getElementsByClassName('char-count'),
2112
}
2213

23-
function updateCounter(element) {
24-
const associatedId = element.getAttribute('for');
25-
if(!associatedId) {
26-
console.error('No associated input found for: ', element);
27-
return;
28-
}
29-
30-
const associatedInput = document.getElementById(associatedId);
31-
if(!associatedInput) {
32-
console.error('No input found with id: ', associatedId);
33-
return;
34-
}
14+
// #region Handle profile image preview
15+
{
16+
ELEMENTS.profileImageInput?.addEventListener('change', () => {
17+
const file = profileImageInput.files[0];
18+
if(!file) return;
3519

36-
const maxChars = Number(associatedInput.getAttribute('maxlength') ?? Infinity);
37-
const currentChars = associatedInput.value.length;
38-
element.textContent = `${currentChars} / ${maxChars}`;
20+
const reader = new FileReader();
21+
reader.onload = () => {
22+
ELEMENTS.profileImagePreview.src = reader.result;
23+
};
24+
reader.readAsDataURL(file);
25+
});
3926
}
40-
}
41-
42-
{ // Handle profile image upload
43-
const profileImageInput = document.getElementById('pfp-input');
44-
profileImageInput?.addEventListener('change', () => {
45-
const file = profileImageInput.files[0];
46-
if(!file) return;
47-
48-
const reader = new FileReader();
49-
reader.onload = () => {
50-
const image = document.getElementById('pfp-preview');
51-
if(image) {
52-
image.src = reader.result;
27+
// #endregion
28+
29+
// #region Char counter
30+
{
31+
for(const counter of ELEMENTS.charCounters) {
32+
const associatedId = counter.getAttribute('for');
33+
if(!associatedId) {
34+
console.error('No associated input found for: ', counter);
35+
continue;
5336
}
54-
};
55-
reader.readAsDataURL(file);
56-
});
57-
}
58-
59-
{ // Handle NSFWJS
60-
const MODEL_TYPE = "MobileNetV2";
61-
const INDEXEDDB_MODEL_KEY = "nsfwjs-model";
62-
async function loadNSFWJS() {
63-
if(!("indexedDB" in window)) {
64-
NSFWJSInstance = await nsfwjs.load(MODEL_TYPE);
65-
return;
66-
}
67-
68-
if(await isModelCached()) {
69-
const cachedInstance = await nsfwjs.load(`indexeddb://${INDEXEDDB_MODEL_KEY}`);
70-
if(cachedInstance) {
71-
NSFWJSInstance = cachedInstance;
72-
return;
37+
38+
const associatedInput = document.getElementById(associatedId);
39+
if(!associatedInput) {
40+
console.error('No input found with id: ', associatedId);
41+
continue;
7342
}
74-
}
7543

76-
const instance = await nsfwjs.load(MODEL_TYPE);
77-
await instance.model.save(`indexeddb://${INDEXEDDB_MODEL_KEY}`);
78-
79-
NSFWJSInstance = instance;
80-
}
81-
82-
async function isModelCached() {
83-
return new Promise((resolve, reject) => {
84-
const openRequest = indexedDB.open("tensorflowjs");
85-
86-
openRequest.onupgradeneeded = () => {
87-
// The database did not previously exist, so it means the model is not saved
88-
resolve(false);
89-
};
90-
91-
openRequest.onsuccess = () => {
92-
const db = openRequest.result;
93-
const transaction = db.transaction("model_info_store", "readonly"); // tensorflow.js uses this object store name
94-
const store = transaction.objectStore("model_info_store");
95-
const getRequest = store.get(INDEXEDDB_MODEL_KEY);
96-
97-
getRequest.onsuccess = () => {
98-
if (getRequest.result) {
99-
resolve(true);
100-
} else {
101-
resolve(false);
102-
}
103-
};
104-
105-
getRequest.onerror = () => {
106-
reject(getRequest.error);
107-
};
108-
};
109-
110-
openRequest.onerror = () => {
111-
reject(openRequest.error);
112-
};
113-
});
44+
associatedInput.addEventListener('input', function() {
45+
const maxChars = Number(associatedInput.getAttribute('maxlength') ?? Infinity);
46+
const currentChars = associatedInput.value.length;
47+
counter.textContent = `${currentChars} / ${maxChars}`;
48+
});
49+
updateCounter(counter);
50+
}
11451
}
115-
116-
loadNSFWJS();
117-
}
52+
// #endregion
53+
}
54+
NSFWJSInstance = await nsfwjs.load("MobileNetV2");

0 commit comments

Comments
 (0)