feat: WIP validate cloud subscription

This commit is contained in:
Zamitto 2024-10-16 01:36:36 -03:00
parent 5c4ddd9b7a
commit 4820109b8d
3 changed files with 59 additions and 27 deletions

View file

@ -115,10 +115,14 @@ export const mergeAchievements = async (
const mergedLocalAchievements = unlockedAchievements.concat(newAchievements); const mergedLocalAchievements = unlockedAchievements.concat(newAchievements);
if (game?.remoteId) { if (game?.remoteId) {
return HydraApi.put("/profile/games/achievements", { return HydraApi.put(
id: game.remoteId, "/profile/games/achievements",
achievements: mergedLocalAchievements, {
}) id: game.remoteId,
achievements: mergedLocalAchievements,
},
{ needsCloud: true }
)
.then((response) => { .then((response) => {
return saveAchievementsOnLocal( return saveAchievementsOnLocal(
response.objectId, response.objectId,

View file

@ -1,16 +1,23 @@
import { userAuthRepository } from "@main/repository"; import {
userAuthRepository,
userSubscriptionRepository,
} from "@main/repository";
import axios, { AxiosError, AxiosInstance } from "axios"; import axios, { AxiosError, AxiosInstance } from "axios";
import { WindowManager } from "./window-manager"; import { WindowManager } from "./window-manager";
import url from "url"; import url from "url";
import { uploadGamesBatch } from "./library-sync"; import { uploadGamesBatch } from "./library-sync";
import { clearGamesRemoteIds } from "./library-sync/clear-games-remote-id"; import { clearGamesRemoteIds } from "./library-sync/clear-games-remote-id";
import { logger } from "./logger"; import { logger } from "./logger";
import { UserNotLoggedInError } from "@shared"; import {
UserNotLoggedInError,
UserWithoutCloudSubscriptionError,
} from "@shared";
import { omit } from "lodash-es"; import { omit } from "lodash-es";
import { appVersion } from "@main/constants"; import { appVersion } from "@main/constants";
interface HydraApiOptions { interface HydraApiOptions {
needsAuth: boolean; needsAuth?: boolean;
needsCloud?: boolean;
} }
export class HydraApi { export class HydraApi {
@ -31,6 +38,19 @@ export class HydraApi {
return this.userAuth.authToken !== ""; return this.userAuth.authToken !== "";
} }
private static async hasCloudSubscription() {
// TODO change this later, this is just a quick test
return userSubscriptionRepository
.findOne({ where: { id: 1 } })
.then((userSubscription) => {
if (userSubscription?.status !== "active") return false;
return (
!userSubscription.expiresAt ||
userSubscription!.expiresAt > new Date()
);
});
}
static async handleExternalAuth(uri: string) { static async handleExternalAuth(uri: string) {
const { payload } = url.parse(uri, true).query; const { payload } = url.parse(uri, true).query;
@ -234,15 +254,28 @@ export class HydraApi {
throw err; throw err;
}; };
private static async validateOptions(options?: HydraApiOptions) {
const needsAuth = options?.needsAuth == undefined || options.needsAuth;
const needsCloud = options?.needsCloud === true;
if (needsAuth) {
if (!this.isLoggedIn()) throw new UserNotLoggedInError();
await this.revalidateAccessTokenIfExpired();
}
if (needsCloud) {
if (!(await this.hasCloudSubscription())) {
throw new UserWithoutCloudSubscriptionError();
}
}
}
static async get<T = any>( static async get<T = any>(
url: string, url: string,
params?: any, params?: any,
options?: HydraApiOptions options?: HydraApiOptions
) { ) {
if (!options || options.needsAuth) { await this.validateOptions(options);
if (!this.isLoggedIn()) throw new UserNotLoggedInError();
await this.revalidateAccessTokenIfExpired();
}
return this.instance return this.instance
.get<T>(url, { params, ...this.getAxiosConfig() }) .get<T>(url, { params, ...this.getAxiosConfig() })
@ -255,10 +288,7 @@ export class HydraApi {
data?: any, data?: any,
options?: HydraApiOptions options?: HydraApiOptions
) { ) {
if (!options || options.needsAuth) { await this.validateOptions(options);
if (!this.isLoggedIn()) throw new UserNotLoggedInError();
await this.revalidateAccessTokenIfExpired();
}
return this.instance return this.instance
.post<T>(url, data, this.getAxiosConfig()) .post<T>(url, data, this.getAxiosConfig())
@ -271,10 +301,7 @@ export class HydraApi {
data?: any, data?: any,
options?: HydraApiOptions options?: HydraApiOptions
) { ) {
if (!options || options.needsAuth) { await this.validateOptions(options);
if (!this.isLoggedIn()) throw new UserNotLoggedInError();
await this.revalidateAccessTokenIfExpired();
}
return this.instance return this.instance
.put<T>(url, data, this.getAxiosConfig()) .put<T>(url, data, this.getAxiosConfig())
@ -287,10 +314,7 @@ export class HydraApi {
data?: any, data?: any,
options?: HydraApiOptions options?: HydraApiOptions
) { ) {
if (!options || options.needsAuth) { await this.validateOptions(options);
if (!this.isLoggedIn()) throw new UserNotLoggedInError();
await this.revalidateAccessTokenIfExpired();
}
return this.instance return this.instance
.patch<T>(url, data, this.getAxiosConfig()) .patch<T>(url, data, this.getAxiosConfig())
@ -299,10 +323,7 @@ export class HydraApi {
} }
static async delete<T = any>(url: string, options?: HydraApiOptions) { static async delete<T = any>(url: string, options?: HydraApiOptions) {
if (!options || options.needsAuth) { await this.validateOptions(options);
if (!this.isLoggedIn()) throw new UserNotLoggedInError();
await this.revalidateAccessTokenIfExpired();
}
return this.instance return this.instance
.delete<T>(url, this.getAxiosConfig()) .delete<T>(url, this.getAxiosConfig())

View file

@ -10,6 +10,13 @@ export class UserNotLoggedInError extends Error {
} }
} }
export class UserWithoutCloudSubscriptionError extends Error {
constructor() {
super("user does not have hydra cloud subscription");
this.name = "UserWithoutCloudSubscriptionError";
}
}
const FORMAT = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; const FORMAT = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
export const formatBytes = (bytes: number): string => { export const formatBytes = (bytes: number): string => {