Added SteamAPI and achievement searching

This commit is contained in:
Gnarwhal 2021-02-18 02:15:09 -05:00
parent b229ff9a15
commit 627cc810ed
Signed by: Gnarwhal
GPG key ID: 0989A73D8C421174
61 changed files with 2781 additions and 903 deletions

View file

@ -25,7 +25,6 @@ const loadSession = async () => {
await fetch(`/api/auth/refresh`, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
@ -52,8 +51,10 @@ const commonTemplates = async () => {
{ section: "right" }
]);
template.apply("navbar-section-left").values([
{ item: "project", title: "Project" },
{ item: "about", title: "About" }
{ item: "achievements", title: "Achievements" },
{ item: "users", title: "Users" },
{ item: "games", title: "Games" },
{ item: "import", title: "Import" }
]);
if (session) {
template.apply("navbar-section-right").values([
@ -62,34 +63,40 @@ const commonTemplates = async () => {
]);
} else {
template.apply("navbar-section-right").values([
{ item: "login", title: "Login" }
{ item: "login", title: "Login" }
]);
}
};
const loadLazyImages = () => {
const imgs = document.querySelectorAll(".lazy-img");
for (const img of imgs) {
img.src = img.dataset.src;
}
}
const connectNavbar = () => {
const navItems = document.querySelectorAll(".navbar-item");
if (!session || !session.admin) {
document.querySelector("#navbar-item-import").remove();
}
for (const item of navItems) {
if (item.dataset.pageName === "logout") {
item.addEventListener("click", (clickEvent) => {
fetch(`/api/auth/logout`, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ key: session.key })
})
.then(response => {
session = undefined;
window.location.href = "/login";
});
session = undefined;
window.location.href = "/login";
});
} else if (item.dataset.pageName === "profile") {
item.addEventListener("click", (clickEvent) => window.location.href = `/profile/${session.id}`);
} else if (item.dataset.pageName === "project") {
item.addEventListener("click", (clickEvent) => window.location.href = `/`);
} else {
item.addEventListener("click", (clickEvent) => window.location.href = `/${item.dataset.pageName}`);
}

View file

@ -1,24 +0,0 @@
const expandTemplates = async () => {
await commonTemplates();
}
const loadFilters = () => {
const filtersButton = document.querySelector("#filter-dropdown-stack");
const filters = document.querySelector("#list-page-filters-flex");
filtersButton.addEventListener("click", (clickEvent) => {
filtersButton.classList.toggle("active");
filters.classList.toggle("active");
});
}
window.addEventListener("load", async (loadEvent) => {
loadRoot();
loadSession();
await expandTemplates();
await template.expand();
connectNavbar();
loadFilters();
});

View file

@ -11,6 +11,7 @@ window.addEventListener("load", async (loadEvent) => {
password: document.querySelector("#password"),
confirm: document.querySelector("#confirm" )
};
fields.email.focus();
const createUser = document.querySelector("#create-user-button");
const login = document.querySelector("#login-button");
@ -80,7 +81,6 @@ window.addEventListener("load", async (loadEvent) => {
freeze();
fetch(`/api/auth/create_user`, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
@ -141,7 +141,6 @@ window.addEventListener("load", async (loadEvent) => {
freeze();
fetch(`/api/auth/login`, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},

View file

@ -2,14 +2,25 @@ let profileId = window.location.pathname.split('/').pop();
let isReturn = false;
let profileData = null;
const loadProfile = () => {
{
const lists = document.querySelectorAll(".profile-list");
const lists = document.querySelectorAll(".profile-list");
const checkLists = () => {
for (const list of lists) {
if (list.querySelectorAll(".profile-entry").length === 0) {
list.parentElement.removeChild(list);
let found = false;
const entries = list.querySelectorAll(".profile-entry");
for (const entry of entries) {
if (window.getComputedStyle(entry).getPropertyValue('display') !== 'none') {
found = true;
break;
}
}
if (!found) {
list.style.display = 'none';
} else {
list.style.display = 'block';
}
}
}
checkLists();
{
const validImageFile = (type) => {
@ -32,7 +43,6 @@ const loadProfile = () => {
if (usernameField.value !== '') {
fetch(`/api/user/${profileId}/username`, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
@ -89,7 +99,6 @@ const loadProfile = () => {
fetch(`/api/user/${profileId}/image`, {
method: 'POST',
mode: 'cors',
body: data
}).then(response => {
if (upload.classList.contains("active")) {
@ -141,6 +150,7 @@ const loadProfile = () => {
for (const platform of platforms) {
platform.classList.toggle("editing");
}
checkLists();
};
editPlatformsButton.addEventListener("click", togglePlatformEdit);
savePlatformsButton.addEventListener("click", togglePlatformEdit);
@ -156,7 +166,6 @@ const loadProfile = () => {
steamButtons[1].addEventListener("click", (clickEvent) => {
fetch(`/api/user/${profileId}/platforms/remove`, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
@ -213,11 +222,11 @@ const expandTemplates = async () => {
template.apply("profile-platforms-list").promise(profileData.then(data =>
data.platforms.map(platform => ({
platform_id: platform.id,
img: `<img class="profile-entry-icon" src="/api/platform/image/${platform.id}" alt="Steam Logo" />`,
img: `<img class="profile-entry-icon" src="/api/platform/${platform.id}/image" alt="Steam Logo" />`,
name: platform.name,
connected: platform.connected ? "connected" : "",
add:
(platform.id === 0 ? `<img id="add-steam" class="platform-add" src="https://community.cloudflare.steamstatic.com/public/images/signinthroughsteam/sits_01.png" alt="Add" />` :
(platform.id === 0 ? `<img id="add-steam" class="platform-add" src="https://steamcdn-a.akamaihd.net/steamcommunity/public/images/steamworks_docs/english/sits_small.png" alt="Add" />` :
(platform.id === 1 ? `<p class="platform-unsupported">Coming soon...</p>` :
(platform.id === 2 ? `<p class="platform-unsupported">Coming soon...</p>` :
"")))
@ -228,6 +237,7 @@ const expandTemplates = async () => {
window.addEventListener("load", async (loadEvent) => {
await loadCommon();
var importing = document.querySelector("#importing");
if (!/\d+/.test(profileId)) {
isReturn = true;
const platform = profileId;
@ -238,6 +248,9 @@ window.addEventListener("load", async (loadEvent) => {
delete session.lastProfile;
}
const importingText = importing.querySelector("#importing-text");
importingText.textContent = `Importing from ${platform}...`;
importing.style.display = `flex`;
if (platform === 'steam') {
const query = new URLSearchParams(window.location.search);
@ -246,9 +259,8 @@ window.addEventListener("load", async (loadEvent) => {
} else {
// Regex courtesy of https://github.com/liamcurry/passport-steam/blob/master/lib/passport-steam/strategy.js
var steamId = /^https?:\/\/steamcommunity\.com\/openid\/id\/(\d+)$/.exec(query.get('openid.claimed_id'))[1];
await fetch("/api/user/platforms/add", {
await fetch(`/api/user/${profileId}/platforms/add`, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
@ -266,13 +278,15 @@ window.addEventListener("load", async (loadEvent) => {
} else {
// Handle error
}
importing.remove();
profileData = fetch(`/api/user/${profileId}`, { method: 'GET', mode: 'cors' })
profileData = fetch(`/api/user/${profileId}`, { method: 'GET' })
.then(response => response.json());
await expandTemplates();
await template.expand();
loadLazyImages();
connectNavbar();
loadProfile();
});

View file

@ -0,0 +1,26 @@
const expandTemplates = async () => {
await commonTemplates();
}
const loadFilters = () => {
const filtersButton = document.querySelector("#filter-dropdown-stack");
const filtersSection = document.querySelector("#list-page-filters-flex");
filtersButton.addEventListener("click", (clickEvent) => {
filtersButton.classList.toggle("active");
filtersSection.classList.toggle("active");
});
const filterCheckboxes = document.querySelectorAll(".list-page-filter-checkbox");
for (const checkbox of filterCheckboxes) {
checkbox.parentElement.addEventListener("click", (clickEvent) => {
checkbox.parentElement.classList.toggle("selected");
})
}
}
const loadCommonSearch = async () => {
await loadCommon();
await expandTemplates();
};

View file

@ -0,0 +1,108 @@
let templateList = null;
let templateText = null;
const saveTemplate = () => {
const templateElement = document.querySelector("#achievement-list-template");
templateList = templateElement.parentElement;
templateText = templateElement.outerHTML;
templateElement.remove();
};
const loadAchievementSearch = () => {
const loading = document.querySelector("#loading-results");
const searchButton = document.querySelector("#achievement-search-button");
const searchField = document.querySelector("#achievement-search-field" );
const completed = document.querySelector("#completed-filter");
const minCompletion = document.querySelector("#min-completion-filter");
const maxCompletion = document.querySelector("#max-completion-filter");
const minDifficulty = document.querySelector("#min-difficulty-filter");
const maxDifficulty = document.querySelector("#max-difficulty-filter");
const minQuality = document.querySelector("#min-quality-filter" );
const maxQuality = document.querySelector("#max-quality-filter" );
let canSearch = true;
const loadList = async () => {
if (canSearch) {
canSearch = false;
const body = {
searchTerm: searchField.value,
userId: completed.classList.contains('active') ? session.id : null,
completed: completed.classList.contains('active'),
minCompletion: minCompletion.value === '' ? null : Number(minCompletion.value),
maxCompletion: maxCompletion.value === '' ? null : Number(maxCompletion.value),
minDifficulty: minDifficulty.value === '' ? null : Number(minDifficulty.value),
maxDifficulty: maxDifficulty.value === '' ? null : Number(maxDifficulty.value),
minQuality: minQuality.value === '' ? null : Number(minQuality.value ),
maxQuality: maxQuality.value === '' ? null : Number(maxQuality.value ),
};
console.log(body);
let successful = true;
if (Number.isNaN(body.minCompletion)) { successful = false; minCompletion.style.backgroundColor = 'var(--error)'; } else { minCompletion.style.backgroundColor = 'var(--foreground)'; }
if (Number.isNaN(body.maxCompletion)) { successful = false; maxCompletion.style.backgroundColor = 'var(--error)'; } else { maxCompletion.style.backgroundColor = 'var(--foreground)'; }
if (Number.isNaN(body.minDifficulty)) { successful = false; minDifficulty.style.backgroundColor = 'var(--error)'; } else { minDifficulty.style.backgroundColor = 'var(--foreground)'; }
if (Number.isNaN(body.maxDifficulty)) { successful = false; maxDifficulty.style.backgroundColor = 'var(--error)'; } else { maxDifficulty.style.backgroundColor = 'var(--foreground)'; }
if (Number.isNaN(body.minQuality )) { successful = false; minQuality.style.backgroundColor = 'var(--error)'; } else { minQuality.style.backgroundColor = 'var(--foreground)'; }
if (Number.isNaN(body.maxQuality )) { successful = false; maxQuality.style.backgroundColor = 'var(--error)'; } else { maxQuality.style.backgroundColor = 'var(--foreground)'; }
if (!successful) {
canSearch = true;
return;
}
for (const entry of templateList.querySelectorAll(".list-page-entry")) {
entry.remove();
}
templateList.innerHTML += templateText;
loading.style.display = 'block';
const data = fetch("/api/achievements", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
})
.then(response => response.json())
template.clear();
template.apply('achievements-page-list').promise(data.then(data => data.map(item => ({
achievement_id: item.ID,
achievement_name: item.name,
game_name: item.game,
completion: item.completion == null ? 'N/A' : item.completion + '%',
difficulty: item.difficulty == null ? 'N/A' : item.difficulty + ' / 10',
quality: item.quality == null ? 'N/A' : item.quality + ' / 10'
}))));
await template.expand();
data.then(data => {
loading.style.display = 'none';
canSearch = true;
loadLazyImages();
});
}
};
searchButton.addEventListener("click", loadList);
searchField.addEventListener("keydown", (keyEvent) => {
if (keyEvent.key === 'Enter') {
loadList();
}
});
loadList();
};
window.addEventListener("load", async (loadEvent) => {
await loadCommonSearch();
saveTemplate();
await template.expand();
connectNavbar();
loadFilters();
await loadAchievementSearch();
});

View file

@ -136,6 +136,10 @@ var template = template || {};
}
};
template.clear = () => {
templateEntryMap.clear();
}
const parseType = (type) => {
let result = type.match(/^\s*(\w+)\s*(?:<(.*)>)?\s*$/);
let id = result[1];