front api service modularized

This commit is contained in:
Zurdi
2024-01-16 00:40:31 +01:00
parent 607b6437a8
commit f7bef9a18a
31 changed files with 491 additions and 472 deletions

View File

@@ -23,20 +23,20 @@ def get_config() -> ConfigResponse:
async def add_platform_binding(request: Request) -> MessageResponse:
"""Add platform binding to the configuration"""
data = await request.form()
fs_slug = data.get("fs_slug")
slug = data.get("slug")
data = await request.json()
fs_slug = data["fs_slug"]
slug = data["slug"]
cm.add_binding(fs_slug, slug)
return {"msg": f"{fs_slug} binded to: {slug} successfully!"}
@protected_route(router.put, "/config/system/platforms", ["platforms.write"])
@protected_route(router.delete, "/config/system/platforms", ["platforms.write"])
async def delete_platform_binding(request: Request) -> MessageResponse:
"""Delete platform binding from the configuration"""
data = await request.form()
fs_slug = data.get("fs_slug")
data = await request.json()
fs_slug = data["fs_slug"]
cm.remove_binding(fs_slug)
return {"msg": f"{fs_slug} bind removed successfully!"}

View File

@@ -2,7 +2,7 @@ import emoji
from decorators.auth import protected_route
from endpoints.responses.search import RomSearchResponse
from fastapi import APIRouter, Request
from handler import dbh, igdbh
from handler import dbromh, igdbh
from logger.logger import log
router = APIRouter()
@@ -24,7 +24,7 @@ async def search_rom(
RomSearchResponse: List of objects with all the matched roms
"""
rom = dbh.get_rom(rom_id)
rom = dbromh.get_roms(rom_id)
search_term = search_term or rom.file_name_no_tags
log.info(emoji.emojize(":magnifying_glass_tilted_right: IGDB Searching"))

View File

@@ -5,7 +5,7 @@ import EditRomDialog from "@/components/Dialog/Rom/EditRom.vue";
import SearchRomDialog from "@/components/Dialog/Rom/SearchRom.vue";
import UploadRomDialog from "@/components/Dialog/Rom/UploadRom.vue";
import GameCard from "@/components/Game/Card/Base.vue";
import api from "@/services/api";
import api_rom from "@/services/api_rom";
import storeRoms from "@/stores/roms";
import { views } from "@/utils";
import { onMounted, ref } from "vue";
@@ -21,7 +21,7 @@ function scrollX(e: WheelEvent) {
}
onMounted(async () => {
const { data: recentData } = await api.getRecentRoms();
const { data: recentData } = await api_rom.getRecentRoms();
romsStore.setRecentRoms(recentData.items);
});
</script>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref } from "vue";
import storeAuth from "@/stores/auth";
import api from "@/services/api";
import api_rom from "@/services/api_rom";
import storeDownload from "@/stores/download";
import AdminMenu from "@/components/Game/AdminMenu/Base.vue";
import type { Rom } from "@/stores/roms";
@@ -17,7 +17,7 @@ const saveFiles = ref(false);
<v-col>
<v-btn
@click="
api.downloadRom({
api_rom.downloadRom({
rom,
files: downloadStore.filesToDownloadMultiFileRom,
})

View File

@@ -3,7 +3,7 @@ import { ref, inject } from "vue";
import type { Emitter } from "mitt";
import type { Events } from "@/types/emitter";
import storeConfig from "@/stores/config";
import api from "@/services/api";
import api_config from "@/services/api_config";
// Props
const show = ref(false);
@@ -19,7 +19,7 @@ emitter?.on("showCreatePlatformBindingDialog", ({ fsSlug = "", slug = "" }) => {
// Functions
function addBindPlatform() {
api.addPlatformBindConfig({
api_config.addPlatformBindConfig({
fsSlug: fsSlugToCreate.value,
slug: slugToCreate.value,
});

View File

@@ -3,7 +3,7 @@ import { ref, inject } from "vue";
import { useRouter } from "vue-router";
import type { Emitter } from "mitt";
import type { Events } from "@/types/emitter";
import api from "@/services/api";
import api_platform from "@/services/api_platform";
import storePlatforms, { type Platform } from "@/stores/platforms";
const router = useRouter();
@@ -20,7 +20,7 @@ async function deletePlatform() {
if (!platform.value) return;
show.value = false;
await api
await api_platform
.deletePlatform({ platform: platform.value })
.then((response) => {
emitter?.emit("snackbarShow", {

View File

@@ -3,7 +3,7 @@ import { ref, inject } from "vue";
import type { Emitter } from "mitt";
import type { Events } from "@/types/emitter";
import storeConfig from "@/stores/config";
import api from "@/services/api";
import api_config from "@/services/api_config";
// Props
const show = ref(false);
@@ -19,7 +19,7 @@ emitter?.on("showDeletePlatformBindingDialog", ({fsSlug, slug}) => {
// Functions
function removeBindPlatform() {
api.deletePlatformBindConfig({ fsSlug: platformBindingFSSlugToDelete.value });
api_config.deletePlatformBindConfig({ fsSlug: platformBindingFSSlugToDelete.value });
configStore.removePlatformBinding(platformBindingFSSlugToDelete.value);
show.value = false;
}

View File

@@ -1,11 +1,11 @@
<script setup lang="ts">
import { ref, inject } from "vue";
import type { Events } from "@/types/emitter";
import type { Emitter } from "mitt";
import { inject, ref } from "vue";
import { useRouter } from "vue-router";
import { useDisplay } from "vuetify";
import type { Emitter } from "mitt";
import type { Events } from "@/types/emitter";
import api from "@/services/api";
import api_rom from "@/services/api_rom";
import storeRoms from "@/stores/roms";
const { xs, mdAndDown, lgAndUp } = useDisplay();
@@ -22,7 +22,7 @@ emitter?.on("showDeleteRomDialog", (romsToDelete) => {
});
async function deleteRoms() {
await api
await api_rom
.deleteRoms({ roms: roms.value, deleteFromFs: deleteFromFs.value })
.then((response) => {
emitter?.emit("snackbarShow", {

View File

@@ -4,7 +4,7 @@ import { useDisplay } from "vuetify";
import type { Emitter } from "mitt";
import type { Events } from "@/types/emitter";
import api, { type UpdateRom } from "@/services/api";
import api_rom, { type UpdateRom } from "@/services/api_rom";
import storeRoms from "@/stores/roms";
const { xs, mdAndDown, lgAndUp } = useDisplay();
@@ -44,7 +44,7 @@ async function updateRom() {
show.value = false;
emitter?.emit("showLoadingDialog", { loading: true, scrim: true });
await api
await api_rom
.updateRom({ rom: rom.value })
.then(({ data }) => {
emitter?.emit("snackbarShow", {

View File

@@ -5,7 +5,7 @@ import { inject, onBeforeUnmount, ref } from "vue";
import { useDisplay } from "vuetify";
import type { IGDBRomType } from "@/__generated__";
import api from "@/services/api";
import api_rom from "@/services/api_rom";
import storeRoms, { type Rom } from "@/stores/roms";
const { xs, mdAndDown, lgAndUp } = useDisplay();
@@ -33,7 +33,7 @@ async function searchRom() {
if (!searching.value) {
searching.value = true;
await api
await api_rom
.searchRom({
romId: rom.value.id,
source: "igdb",
@@ -65,7 +65,7 @@ async function updateRom(matchedRom: IGDBRomType) {
rom.value.url_cover = matchedRom.url_cover;
rom.value.url_screenshots = matchedRom.url_screenshots;
await api
await api_rom
.updateRom({ rom: rom.value, renameAsIGDB: renameAsIGDB.value })
.then(({ data }) => {
emitter?.emit("snackbarShow", {

View File

@@ -6,7 +6,7 @@ import type { Emitter } from "mitt";
import type { Events } from "@/types/emitter";
import socket from "@/services/socket";
import api from "@/services/api";
import api_rom from "@/services/api_rom";
import storeScanning from "@/stores/scanning";
const { xs, mdAndDown, lgAndUp } = useDisplay();
@@ -51,7 +51,7 @@ async function uploadRoms() {
color: "romm-accent-1",
});
await api
await api_rom
.uploadRoms({
romsToUpload: romsToUpload.value,
platform: route.params.platform as string,

View File

@@ -3,7 +3,7 @@ import { ref, inject } from "vue";
import type { Emitter } from "mitt";
import type { Events } from "@/types/emitter";
import api from "@/services/api";
import api_user from "@/services/api_user";
import storeUsers from "@/stores/users";
const user = ref({
@@ -21,7 +21,7 @@ emitter?.on("showCreateUserDialog", () => {
// Functions
async function createUser() {
await api.createUser(user.value)
await api_user.createUser(user.value)
.then(({ data }) => {
usersStore.add(data);
})

View File

@@ -2,7 +2,7 @@
import { ref, inject } from "vue";
import type { Emitter } from "mitt";
import type { UserItem, Events } from "@/types/emitter";
import api from "@/services/api";
import api_user from "@/services/api_user";
import storeUsers from "@/stores/users";
const user = ref<UserItem | null>(null);
@@ -19,7 +19,7 @@ emitter?.on("showDeleteUserDialog", (userToDelete) => {
async function deleteUser() {
if (!user.value) return;
await api
await api_user
.deleteUser(user.value)
.then(() => {
if (user.value) usersStore.remove(user.value.id);

View File

@@ -3,7 +3,7 @@ import { ref, inject } from "vue";
import type { Emitter } from "mitt";
import type { Events, UserItem } from "@/types/emitter";
import api from "@/services/api";
import api_user from "@/services/api_user";
import { defaultAvatarPath } from "@/utils";
import storeUsers from "@/stores/users";
@@ -21,7 +21,7 @@ emitter?.on("showEditUserDialog", (userToEdit) => {
function editUser() {
if (!user.value) return;
api
api_user
.updateUser(user.value)
.then(({ data }) => {
emitter?.emit("snackbarShow", {

View File

@@ -1,12 +1,12 @@
<script setup lang="ts">
import { inject, ref } from "vue";
import { useRouter } from "vue-router";
import type { Emitter } from "mitt";
import type { Events } from "@/types/emitter";
import api_identity from "@/services/api_identity";
import storeAuth from "@/stores/auth";
import storeHeartbeat from "@/stores/heartbeat";
import type { Events } from "@/types/emitter";
import { defaultAvatarPath } from "@/utils";
import api from "@/services/api";
import type { Emitter } from "mitt";
import { inject, ref } from "vue";
import { useRouter } from "vue-router";
// Props
defineProps<{ rail?: boolean }>();
@@ -27,7 +27,7 @@ function dismissNewVersion() {
}
async function logout() {
api
api_identity
.logout()
.then(({ data }) => {
emitter?.emit("snackbarShow", {

View File

@@ -8,7 +8,7 @@ import storeAuth from "@/stores/auth";
import storeRoms from "@/stores/roms";
import socket from "@/services/socket";
import storeScanning from "@/stores/scanning";
import api from "@/services/api";
import api_rom from "@/services/api_rom";
// Event listeners bus
const emitter = inject<Emitter<Events>>("emitter");
@@ -71,7 +71,7 @@ function selectAllRoms() {
function onDownload() {
romsStore.selectedRoms.forEach((rom) => {
api.downloadRom({ rom });
api_rom.downloadRom({ rom });
});
}
</script>

View File

@@ -1,6 +1,5 @@
<script setup lang="ts">
import { ref } from "vue";
import api from "@/services/api";
import api_rom from "@/services/api_rom";
import storeDownload from "@/stores/download";
import storeAuth from "@/stores/auth";
import AdminMenu from "@/components/Game/AdminMenu/Base.vue";
@@ -18,7 +17,7 @@ const downloadStore = storeDownload();
<v-col class="pa-0">
<v-btn
class="action-bar-btn"
@click="api.downloadRom({ rom })"
@click="api_rom.downloadRom({ rom })"
:disabled="downloadStore.value.includes(rom.id)"
icon="mdi-download"
size="x-small"

View File

@@ -4,7 +4,7 @@ import { useRouter } from "vue-router";
import { VDataTable } from "vuetify/labs/VDataTable";
import AdminMenu from "@/components/Game/AdminMenu/Base.vue";
import api from "@/services/api";
import api_rom from "@/services/api_rom";
import storeAuth from "@/stores/auth";
import storeDownload from "@/stores/download";
import storeRoms from "@/stores/roms";
@@ -123,7 +123,7 @@ function rowClick(_: Event, row: any) {
<v-btn
class="ma-1"
rounded="0"
@click.stop="api.downloadRom({ rom: item.raw })"
@click.stop="api_rom.downloadRom({ rom: item.raw })"
:disabled="downloadStore.value.includes(item.raw.id)"
download
size="small"

View File

@@ -1,20 +1,5 @@
import type {
AddRomsResponse,
CursorPage_RomSchema_,
EnhancedRomSchema,
MessageResponse,
PlatformSchema,
RomSchema,
RomSearchResponse,
SaveSchema,
StateSchema,
UserSchema,
} from "@/__generated__";
import router from "@/plugins/router";
import socket from "@/services/socket";
import storeDownload from "@/stores/download";
import type { Rom } from "@/stores/roms";
import type { User } from "@/stores/users";
import axios from "axios";
export const api = axios.create({ baseURL: "/api", timeout: 120000 });
@@ -31,395 +16,3 @@ api.interceptors.response.use(
return Promise.reject(error);
}
);
// === Identity ===
async function login(username: string, password: string) {
return api.post(
"/login",
{},
{
auth: {
username: username,
password: password,
},
}
);
}
async function logout() {
return api.post("/logout", {});
}
// === Identity ===
// === Platforms ===
async function getPlatforms(): Promise<{ data: PlatformSchema[] }> {
return api.get("/platforms");
}
async function getPlatform(
id: number | undefined
): Promise<{ data: PlatformSchema }> {
return api.get(`/platforms/${id}`);
}
async function updatePlatform({
platform,
}: {
platform: PlatformSchema;
}): Promise<{ data: MessageResponse }> {
return api.delete(`/platforms/${platform.id}`);
}
async function deletePlatform({
platform,
}: {
platform: PlatformSchema;
}): Promise<{ data: MessageResponse }> {
return api.delete(`/platforms`, { data: { platforms: [platform.id] } });
}
// === Platforms ===
// === Roms ===
async function uploadRoms({
platform,
romsToUpload,
}: {
platform: string;
romsToUpload: File[];
}): Promise<{ data: AddRomsResponse }> {
let formData = new FormData();
romsToUpload.forEach((rom) => formData.append("roms", rom));
return api.put("/roms", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
params: { platform_slug: platform },
});
}
async function getRoms({
platformId,
size = 60,
cursor = "",
searchTerm = "",
orderBy = "name",
orderDir = "asc",
}: {
platformId: number;
size?: number;
cursor?: string | null;
searchTerm?: string;
orderBy?: string;
orderDir?: string;
}): Promise<{ data: CursorPage_RomSchema_ }> {
return api.get(`/roms`, {
params: {
platform_id: platformId,
size: size,
cursor: cursor,
search_term: searchTerm,
order_by: orderBy,
order_dir: orderDir,
},
});
}
async function getRecentRoms(): Promise<{ data: CursorPage_RomSchema_ }> {
return api.get("/roms", {
params: { size: 15, order_by: "id", order_dir: "desc" },
});
}
async function getRom({
romId,
}: {
romId: number;
}): Promise<{ data: EnhancedRomSchema }> {
return api.get(`/roms/${romId}`);
}
function clearRomFromDownloads({ id }: { id: number }) {
const downloadStore = storeDownload();
downloadStore.remove(id);
// Disconnect socket when no more downloads are in progress
if (downloadStore.value.length === 0) socket.disconnect();
}
async function searchRom({
romId,
source,
searchTerm,
searchBy,
}: {
romId: number;
source: string;
searchTerm: string;
searchBy: string;
}): Promise<{ data: RomSearchResponse }> {
return api.get("/search/roms", {
params: {
rom_id: romId,
source: source,
search_term: searchTerm,
search_by: searchBy,
},
});
}
// Listen for multi-file download completion events
socket.on("download:complete", clearRomFromDownloads);
// Used only for multi-file downloads
async function downloadRom({
rom,
files = [],
}: {
rom: Rom;
files?: string[];
}) {
// Force download of all multirom-parts when no part is selected
if (files.length == 0) {
files = rom.files;
}
var files_params = "";
files.forEach((file) => {
files_params += `files=${file}&`;
});
const a = document.createElement("a");
a.href = `/api/roms/${rom.id}/content?${files_params}`;
a.download = `${rom.name}.zip`;
a.click();
// Only connect socket if multi-file download
if (rom.multi) {
if (!socket.connected) socket.connect();
storeDownload().add(rom.id);
// Clear download state after 60 seconds in case error/timeout
setTimeout(() => {
clearRomFromDownloads(rom);
}, 60 * 1000);
}
}
export type UpdateRom = Rom & {
artwork?: File[];
};
async function updateRom({
rom,
renameAsIGDB = false,
}: {
rom: UpdateRom;
renameAsIGDB?: boolean;
}): Promise<{ data: RomSchema }> {
var formData = new FormData();
formData.append("igdb_id", rom.igdb_id?.toString() || "");
formData.append("name", rom.name || "");
formData.append("slug", rom.slug || "");
formData.append("file_name", rom.file_name);
formData.append("summary", rom.summary || "");
formData.append("url_cover", rom.url_cover);
formData.append("url_screenshots", JSON.stringify(rom.url_screenshots));
if (rom.artwork) formData.append("artwork", rom.artwork[0]);
return api.put(`/roms/${rom.id}`, formData, {
params: { rename_as_igdb: renameAsIGDB },
});
}
async function deleteRoms({
roms,
deleteFromFs = false,
}: {
roms: Rom[];
deleteFromFs: boolean;
}): Promise<{ data: MessageResponse }> {
return api.delete("/roms", {
data: { roms: roms.map((r) => r.id), delete_from_fs: deleteFromFs },
});
}
// === Roms ===
// === Users ===
async function fetchUsers(): Promise<{ data: UserSchema[] }> {
return api.get("/users");
}
async function fetchUser(user: User): Promise<{ data: UserSchema }> {
return api.get(`/users/${user.id}`);
}
async function fetchCurrentUser(): Promise<{ data: UserSchema | null }> {
return api.get("/users/me");
}
async function createUser({
username,
password,
role,
}: {
username: string;
password: string;
role: string;
}): Promise<{ data: UserSchema }> {
return api.post("/users", {}, { params: { username, password, role } });
}
async function updateUser({
id,
username,
password,
role,
enabled,
avatar,
}: {
id: number;
username: string;
password: string;
role: string;
enabled: boolean;
avatar?: File[];
}): Promise<{ data: UserSchema }> {
return api.put(
`/users/${id}`,
{
avatar: avatar ? avatar[0] : null,
},
{
headers: {
"Content-Type": avatar ? "multipart/form-data" : "application/json",
},
params: { username, password, role, enabled },
}
);
}
async function deleteUser(user: User): Promise<{ data: MessageResponse }> {
return api.delete(`/users/${user.id}`);
}
// === Users ===
// === Saves ===
async function uploadSaves({ rom, saves }: { rom: Rom; saves: File[] }) {
let formData = new FormData();
saves.forEach((save) => formData.append("saves", save));
console.log(saves);
return api.post("/saves", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
params: { rom_id: rom.id },
});
}
async function deleteSaves({
saves,
deleteFromFs,
}: {
saves: SaveSchema[];
deleteFromFs: boolean;
}) {
return api.delete("/saves", {
data: {
saves: saves.map((s) => s.id),
delete_from_fs: deleteFromFs,
},
});
}
// === Saves ===
// === States ===
async function uploadStates({ rom, states }: { rom: Rom; states: File[] }) {
let formData = new FormData();
states.forEach((state) => formData.append("states", state));
return api.post("/states", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
params: { rom_id: rom.id },
});
}
async function deleteStates({
states,
deleteFromFs,
}: {
states: StateSchema[];
deleteFromFs: boolean;
}) {
return api.put("/states", {
data: {
states: states.map((s) => s.id),
delete_from_fs: deleteFromFs,
},
});
}
// === States ===
// === Config ===
async function addPlatformBindConfig({
fsSlug,
slug,
}: {
fsSlug: string;
slug: string;
}): Promise<{ data: MessageResponse }> {
return api.post("/config/system/platforms", { fs_slug: fsSlug, slug: slug });
}
async function deletePlatformBindConfig({
fsSlug,
}: {
fsSlug: string;
}): Promise<{ data: MessageResponse }> {
return api.delete("/config/system/platforms", { data: { fs_slug: fsSlug } });
}
// === Config ===
export default {
login,
logout,
getPlatforms,
getPlatform,
deletePlatform,
uploadRoms,
getRoms,
getRecentRoms,
getRom,
downloadRom,
searchRom,
updateRom,
deleteRoms,
createUser,
fetchUsers,
fetchUser,
fetchCurrentUser,
updateUser,
deleteUser,
uploadSaves,
deleteSaves,
uploadStates,
deleteStates,
addPlatformBindConfig,
deletePlatformBindConfig,
};

View File

@@ -0,0 +1,27 @@
import type { MessageResponse } from "@/__generated__";
import { api } from "@/services/api";
export const api_config = api;
async function addPlatformBindConfig({
fsSlug,
slug,
}: {
fsSlug: string;
slug: string;
}): Promise<{ data: MessageResponse }> {
return api.post("/config/system/platforms", { fs_slug: fsSlug, slug: slug });
}
async function deletePlatformBindConfig({
fsSlug,
}: {
fsSlug: string;
}): Promise<{ data: MessageResponse }> {
return api.delete("/config/system/platforms", { data: { fs_slug: fsSlug } });
}
export default {
addPlatformBindConfig,
deletePlatformBindConfig,
};

View File

@@ -0,0 +1,29 @@
import type { MessageResponse } from "@/__generated__";
import { api } from "@/services/api";
export const api_identity = api;
async function login(
username: string,
password: string
): Promise<{ data: MessageResponse }> {
return api.post(
"/login",
{},
{
auth: {
username: username,
password: password,
},
}
);
}
async function logout(): Promise<{ data: MessageResponse }> {
return api.post("/logout", {});
}
export default {
login,
logout,
};

View File

@@ -0,0 +1,36 @@
import type { MessageResponse, PlatformSchema } from "@/__generated__";
import { api } from "@/services/api";
export const api_platform = api;
async function getPlatforms(): Promise<{ data: PlatformSchema[] }> {
return api.get("/platforms");
}
async function getPlatform(
id: number | undefined
): Promise<{ data: PlatformSchema }> {
return api.get(`/platforms/${id}`);
}
async function updatePlatform({
platform,
}: {
platform: PlatformSchema;
}): Promise<{ data: MessageResponse }> {
return api.delete(`/platforms/${platform.id}`);
}
async function deletePlatform({
platform,
}: {
platform: PlatformSchema;
}): Promise<{ data: MessageResponse }> {
return api.delete(`/platforms`, { data: { platforms: [platform.id] } });
}
export default {
getPlatforms,
getPlatform,
deletePlatform,
};

View File

@@ -0,0 +1,189 @@
import type {
AddRomsResponse,
CursorPage_RomSchema_,
EnhancedRomSchema,
MessageResponse,
RomSchema,
RomSearchResponse,
} from "@/__generated__";
import { api } from "@/services/api";
import socket from "@/services/socket";
import storeDownload from "@/stores/download";
import type { Rom } from "@/stores/roms";
export const api_rom = api;
async function uploadRoms({
platform,
romsToUpload,
}: {
platform: string;
romsToUpload: File[];
}): Promise<{ data: AddRomsResponse }> {
let formData = new FormData();
romsToUpload.forEach((rom) => formData.append("roms", rom));
return api.put("/roms", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
params: { platform_slug: platform },
});
}
async function getRoms({
platformId,
size = 60,
cursor = "",
searchTerm = "",
orderBy = "name",
orderDir = "asc",
}: {
platformId: number;
size?: number;
cursor?: string | null;
searchTerm?: string;
orderBy?: string;
orderDir?: string;
}): Promise<{ data: CursorPage_RomSchema_ }> {
return api.get(`/roms`, {
params: {
platform_id: platformId,
size: size,
cursor: cursor,
search_term: searchTerm,
order_by: orderBy,
order_dir: orderDir,
},
});
}
async function getRecentRoms(): Promise<{ data: CursorPage_RomSchema_ }> {
return api.get("/roms", {
params: { size: 15, order_by: "id", order_dir: "desc" },
});
}
async function getRom({
romId,
}: {
romId: number;
}): Promise<{ data: EnhancedRomSchema }> {
return api.get(`/roms/${romId}`);
}
function clearRomFromDownloads({ id }: { id: number }) {
const downloadStore = storeDownload();
downloadStore.remove(id);
// Disconnect socket when no more downloads are in progress
if (downloadStore.value.length === 0) socket.disconnect();
}
async function searchRom({
romId,
source,
searchTerm,
searchBy,
}: {
romId: number;
source: string;
searchTerm: string;
searchBy: string;
}): Promise<{ data: RomSearchResponse }> {
return api.get("/search/roms", {
params: {
rom_id: romId,
source: source,
search_term: searchTerm,
search_by: searchBy,
},
});
}
// Listen for multi-file download completion events
socket.on("download:complete", clearRomFromDownloads);
// Used only for multi-file downloads
async function downloadRom({
rom,
files = [],
}: {
rom: Rom;
files?: string[];
}) {
// Force download of all multirom-parts when no part is selected
if (files.length == 0) {
files = rom.files;
}
var files_params = "";
files.forEach((file) => {
files_params += `files=${file}&`;
});
const a = document.createElement("a");
a.href = `/api/roms/${rom.id}/content?${files_params}`;
a.download = `${rom.name}.zip`;
a.click();
// Only connect socket if multi-file download
if (rom.multi) {
if (!socket.connected) socket.connect();
storeDownload().add(rom.id);
// Clear download state after 60 seconds in case error/timeout
setTimeout(() => {
clearRomFromDownloads(rom);
}, 60 * 1000);
}
}
export type UpdateRom = Rom & {
artwork?: File[];
};
async function updateRom({
rom,
renameAsIGDB = false,
}: {
rom: UpdateRom;
renameAsIGDB?: boolean;
}): Promise<{ data: RomSchema }> {
var formData = new FormData();
formData.append("igdb_id", rom.igdb_id?.toString() || "");
formData.append("name", rom.name || "");
formData.append("slug", rom.slug || "");
formData.append("file_name", rom.file_name);
formData.append("summary", rom.summary || "");
formData.append("url_cover", rom.url_cover);
formData.append("url_screenshots", JSON.stringify(rom.url_screenshots));
if (rom.artwork) formData.append("artwork", rom.artwork[0]);
return api.put(`/roms/${rom.id}`, formData, {
params: { rename_as_igdb: renameAsIGDB },
});
}
async function deleteRoms({
roms,
deleteFromFs = false,
}: {
roms: Rom[];
deleteFromFs: boolean;
}): Promise<{ data: MessageResponse }> {
return api.delete("/roms", {
data: { roms: roms.map((r) => r.id), delete_from_fs: deleteFromFs },
});
}
export default {
uploadRoms,
getRoms,
getRecentRoms,
getRom,
downloadRom,
searchRom,
updateRom,
deleteRoms,
};

View File

@@ -0,0 +1,37 @@
import type { SaveSchema } from "@/__generated__";
import { api } from "@/services/api";
import type { Rom } from "@/stores/roms";
export const api_save = api;
async function uploadSaves({ rom, saves }: { rom: Rom; saves: File[] }) {
let formData = new FormData();
saves.forEach((save) => formData.append("saves", save));
console.log(saves);
return api.post("/saves", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
params: { rom_id: rom.id },
});
}
async function deleteSaves({
saves,
deleteFromFs,
}: {
saves: SaveSchema[];
deleteFromFs: boolean;
}) {
return api.delete("/saves", {
data: {
saves: saves.map((s) => s.id),
delete_from_fs: deleteFromFs,
},
});
}
export default {
deleteSaves,
uploadSaves,
};

View File

@@ -0,0 +1,37 @@
import type { StateSchema } from "@/__generated__";
import { api } from "@/services/api";
import type { Rom } from "@/stores/roms";
export const api_state = api;
async function uploadStates({ rom, states }: { rom: Rom; states: File[] }) {
let formData = new FormData();
states.forEach((state) => formData.append("states", state));
return api.post("/states", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
params: { rom_id: rom.id },
});
}
async function deleteStates({
states,
deleteFromFs,
}: {
states: StateSchema[];
deleteFromFs: boolean;
}) {
return api.put("/states", {
data: {
states: states.map((s) => s.id),
delete_from_fs: deleteFromFs,
},
});
}
export default {
uploadStates,
deleteStates,
};

View File

@@ -0,0 +1,71 @@
import type { MessageResponse, UserSchema } from "@/__generated__";
import { api } from "@/services/api";
import type { User } from "@/stores/users";
export const api_user = api;
async function fetchUsers(): Promise<{ data: UserSchema[] }> {
return api.get("/users");
}
async function fetchUser(user: User): Promise<{ data: UserSchema }> {
return api.get(`/users/${user.id}`);
}
async function fetchCurrentUser(): Promise<{ data: UserSchema | null }> {
return api.get("/users/me");
}
async function createUser({
username,
password,
role,
}: {
username: string;
password: string;
role: string;
}): Promise<{ data: UserSchema }> {
return api.post("/users", {}, { params: { username, password, role } });
}
async function updateUser({
id,
username,
password,
role,
enabled,
avatar,
}: {
id: number;
username: string;
password: string;
role: string;
enabled: boolean;
avatar?: File[];
}): Promise<{ data: UserSchema }> {
return api.put(
`/users/${id}`,
{
avatar: avatar ? avatar[0] : null,
},
{
headers: {
"Content-Type": avatar ? "multipart/form-data" : "application/json",
},
params: { username, password, role, enabled },
}
);
}
async function deleteUser(user: User): Promise<{ data: MessageResponse }> {
return api.delete(`/users/${user.id}`);
}
export default {
createUser,
fetchUsers,
fetchUser,
fetchCurrentUser,
updateUser,
deleteUser,
};

View File

@@ -19,7 +19,8 @@ import LoadingDialog from "@/components/Dialog/Loading.vue";
import DeleteRomDialog from "@/components/Dialog/Rom/DeleteRom.vue";
import EditRomDialog from "@/components/Dialog/Rom/EditRom.vue";
import SearchRomDialog from "@/components/Dialog/Rom/SearchRom.vue";
import api from "@/services/api";
import api_rom from "@/services/api_rom";
import api_platform from "@/services/api_platform";
const route = useRoute();
const rom = ref<EnhancedRomSchema>();
@@ -31,7 +32,7 @@ const emitter = inject<Emitter<Events>>("emitter");
async function fetchDetails() {
if (!route.params.rom) return;
await api
await api_rom
.getRom({ romId: parseInt(route.params.rom as string) })
.then((response) => {
rom.value = response.data;
@@ -48,7 +49,7 @@ async function fetchDetails() {
emitter?.emit("showLoadingDialog", { loading: false, scrim: false });
});
await api
await api_platform
.getPlatform(rom.value?.platform_id)
.then((response) => {
platform.value = response.data;

View File

@@ -15,7 +15,7 @@ import GalleryAppBar from "@/components/Gallery/AppBar/Base.vue";
import FabMenu from "@/components/Gallery/FabMenu/Base.vue";
import GameCard from "@/components/Game/Card/Base.vue";
import GameDataTable from "@/components/Game/DataTable/Base.vue";
import api from "@/services/api";
import api_rom from "@/services/api_rom";
import storeGalleryFilter from "@/stores/galleryFilter";
import storeGalleryView from "@/stores/galleryView";
import storeRoms from "@/stores/roms";
@@ -62,7 +62,7 @@ async function fetchRoms(platformId: number) {
scrim: false,
});
await api
await api_rom
.getRoms({
platformId: platformId,
cursor: isFiltered ? searchCursor.value : cursor.value,

View File

@@ -6,7 +6,8 @@ import { useDisplay } from "vuetify";
import AppBar from "@/components/AppBar/Base.vue";
import Drawer from "@/components/Drawer/Base.vue";
import api from "@/services/api";
import api_user from "@/services/api_user";
import api_platform from "@/services/api_platform";
import storeAuth from "@/stores/auth";
import storePlatforms from "@/stores/platforms";
import storeScanning from "@/stores/scanning";
@@ -20,16 +21,16 @@ const auth = storeAuth();
// Event listeners bus
const emitter = inject<Emitter<Events>>("emitter");
emitter?.on("refreshDrawer", async () => {
const { data: platformData } = await api.getPlatforms();
const { data: platformData } = await api_platform.getPlatforms();
platformsStore.set(platformData);
});
// Functions
onMounted(async () => {
try {
const { data: platforms } = await api.getPlatforms();
const { data: platforms } = await api_platform.getPlatforms();
platformsStore.set(platforms);
const { data: currentUser } = await api.fetchCurrentUser();
const { data: currentUser } = await api_user.fetchCurrentUser();
if (currentUser) auth.setUser(currentUser);
emitter?.emit("refreshDrawer", null);
} catch (error) {

View File

@@ -3,8 +3,7 @@ import type { Events } from "@/types/emitter";
import type { Emitter } from "mitt";
import { inject, onBeforeMount, ref } from "vue";
import { useRouter } from "vue-router";
import api from "@/services/api";
import api_identity from "@/services/api_identity";
import storeAuth from "@/stores/auth";
// Props
@@ -18,7 +17,7 @@ const logging = ref(false);
function login() {
logging.value = true;
api
api_identity
.login(username.value, password.value)
.then(() => {
const next = (router.currentRoute.value.query?.next || "/").toString();

View File

@@ -7,7 +7,7 @@ import { VDataTable } from "vuetify/labs/VDataTable";
import CreateUserDialog from "@/components/Dialog/User/CreateUser.vue";
import DeleteUserDialog from "@/components/Dialog/User/DeleteUser.vue";
import EditUserDialog from "@/components/Dialog/User/EditUser.vue";
import api from "@/services/api";
import api_user from "@/services/api_user";
import storeAuth from "@/stores/auth";
import storeUsers from "@/stores/users";
import type { UserItem } from "@/types/emitter";
@@ -57,7 +57,7 @@ const usersPerPage = ref(5);
const userSearch = ref("");
function disableUser(user: UserItem) {
api.updateUser(user).catch(({ response, message }) => {
api_user.updateUser(user).catch(({ response, message }) => {
emitter?.emit("snackbarShow", {
msg: `Unable to disable/enable user: ${
response?.data?.detail || response?.statusText || message
@@ -70,7 +70,7 @@ function disableUser(user: UserItem) {
}
onMounted(() => {
api
api_user
.fetchUsers()
.then(({ data }) => {
usersStore.set(data);