diff --git a/packages/app/.config.js b/packages/app/.config.js index 94a26ec5..fe4b4d2b 100755 --- a/packages/app/.config.js +++ b/packages/app/.config.js @@ -13,10 +13,11 @@ const aliases = { pages: path.join(__dirname, "src/pages"), theme: path.join(__dirname, "src/theme"), components: path.join(__dirname, "src/components"), - models: path.join(__dirname, "src/models"), utils: path.join(__dirname, "src/utils"), layouts: path.join(__dirname, "src/layouts"), hooks: path.join(__dirname, "src/hooks"), + "comty.js": path.join(__dirname, "../", "comty.js", "src"), + models: path.join(__dirname, "../comty.js/src/models"), } module.exports = (config = {}) => { @@ -36,7 +37,7 @@ module.exports = (config = {}) => { config.server.port = process.env.listenPort ?? 8000 config.server.host = "0.0.0.0" config.server.fs = { - allow: [".."] + allow: ["..", "../../"], } config.envDir = path.join(__dirname, "environments") diff --git a/packages/app/config/index.js b/packages/app/config/index.js index 50e330c0..7d2d926d 100755 --- a/packages/app/config/index.js +++ b/packages/app/config/index.js @@ -2,30 +2,6 @@ import packagejson from "../package.json" import defaultTheme from "../constants/defaultTheme.json" import defaultSoundPack from "../constants/defaultSoundPack.json" -const envOrigins = { - "localhost": { - mainApi: `http://${window.location.hostname}:3010`, - messagingApi: `http://${window.location.hostname}:3020`, - livestreamingApi: `http://${window.location.hostname}:3030`, - }, - "development": { - mainApi: `https://indev_api.comty.app`, - messagingApi: `https://indev_messaging_api.comty.app`, - livestreamingApi: `https://indev_livestreaming_api.comty.app`, - }, - "production": { - mainApi: "https://api.comty.app", - messagingApi: `https://messaging_api.comty.app`, - livestreamingApi: `https://livestreaming_api.comty.app`, - } -} - -function composeRemote(path) { - return window.location.hostname.includes("localhost") ? envOrigins["localhost"][path] : envOrigins[process.env.NODE_ENV][path] -} - -console.log(`Config loaded with mode: [${process.env.NODE_ENV}]`) - export default { package: packagejson, defaultTheme: defaultTheme, @@ -61,11 +37,6 @@ export default { ragestudio_alt: "https://storage.ragestudio.net/rstudio/branding/ragestudio/iso/ragestudio.svg", ragestudio_full: "https://storage.ragestudio.net/rstudio/branding/ragestudio/labeled/ragestudio-labeled_white.svg", }, - remotes: { - mainApi: composeRemote("mainApi"), - messagingApi: composeRemote("messagingApi"), - livestreamingApi: composeRemote("livestreamingApi"), - }, app: { title: packagejson.name, siteName: "Comty™", diff --git a/packages/app/constants/settings/about/index.jsx b/packages/app/constants/settings/about/index.jsx index 030630f3..24059dae 100755 --- a/packages/app/constants/settings/about/index.jsx +++ b/packages/app/constants/settings/about/index.jsx @@ -81,9 +81,9 @@ export default { const instance = app.cores.api.instance() if (instance) { - setServerOrigin(instance.origin) + setServerOrigin(instance.mainOrigin) - if (instance.origin.startsWith("https")) { + if (instance.mainOrigin.startsWith("https")) { setSecureConnection(true) } } diff --git a/packages/app/constants/settings/components/changePassword/index.jsx b/packages/app/constants/settings/components/changePassword/index.jsx index 5134df4b..a3809dc6 100755 --- a/packages/app/constants/settings/components/changePassword/index.jsx +++ b/packages/app/constants/settings/components/changePassword/index.jsx @@ -1,7 +1,7 @@ import React from "react" import * as antd from "antd" -import { UserModel } from "models" +import UserModel from "models/user" import { Icons } from "components/Icons" import "./index.less" diff --git a/packages/app/package.json b/packages/app/package.json index 4efa4536..356af713 100755 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -48,6 +48,7 @@ "axios": "1.1.3", "buffer": "^6.0.3", "classnames": "2.3.1", + "dexie": "^3.2.3", "dompurify": "^3.0.0", "electron-is": "^3.0.0", "electron-log": "^4.4.8", diff --git a/packages/app/src/cores/api/index.js b/packages/app/src/cores/api/index.js old mode 100755 new mode 100644 index b05a75ea..437ea5e8 --- a/packages/app/src/cores/api/index.js +++ b/packages/app/src/cores/api/index.js @@ -1,18 +1,14 @@ -import React from "react" import Core from "evite/src/core" -import { Bridge } from "linebridge/dist/client" -import config from "config" -import { SessionModel } from "models" +import createClient from "comty.js" -export default class ApiCore extends Core { +import measurePing from "comty.js/handlers/measurePing" +import request from "comty.js/handlers/request" +import useRequest from "comty.js/hooks/useRequest" + +export default class APICore extends Core { static refName = "api" static namespace = "api" - static depends = ["settings"] - - excludedExpiredExceptionURL = ["/session/regenerate"] - - onExpiredExceptionEvent = false instance = null @@ -20,369 +16,53 @@ export default class ApiCore extends Core { instance: function () { return this.instance }.bind(this), - useRequest: this.useRequest, - customRequest: this.customRequest.bind(this), - request: this.request.bind(this), - withEndpoints: this.withEndpoints.bind(this), - attach: this.attach.bind(this), - createBridge: this.createBridge.bind(this), - autenticateWS: this.autenticateWS.bind(this), + customRequest: request, listenEvent: this.listenEvent.bind(this), unlistenEvent: this.unlistenEvent.bind(this), - measurePing: this.measurePing.bind(this), + measurePing: measurePing, + useRequest: useRequest, } - async attach() { - // get remotes origins from config - const defaultRemotes = config.remotes + listenEvent(key, handler, instance) { + this.instance.wsInstances[instance ?? "default"].on(key, handler) + } - // get storaged remotes origins - const storedRemotes = await app.cores.settings.get("remotes") ?? {} + unlistenEvent(key, handler, instance) { + this.instance.wsInstances[instance ?? "default"].off(key, handler) + } - const origin = storedRemotes.mainApi ?? defaultRemotes.mainApi - - this.instance = this.createBridge({ - origin, + async onInitialize() { + this.instance = await createClient({ + useWs: true, }) - await this.instance.initialize() + this.instance.eventBus.on("auth:login_success", () => { + app.eventBus.emit("auth:login_success") + }) - console.debug(`[API] Attached to ${origin}`, this.instance) + this.instance.eventBus.on("auth:logout_success", () => { + app.eventBus.emit("auth:logout_success") + }) + + this.instance.eventBus.on("session.invalid", (error) => { + app.eventBus.emit("session.invalid", error) + }) + + // make a basic request to check if the API is available + await this.instance.instances["default"]({ + method: "GET", + url: "/ping", + }).catch((error) => { + console.error("[API] Ping error", error) + + throw new Error(` + Could not connect to the API. + Please check your connection and try again. + `) + }) + + console.debug("[API] Attached to", this.instance) return this.instance } - - useRequest(method, ...args) { - if (typeof method !== "function") { - throw new Error("useRequest: method must be a function") - } - - const [loading, setLoading] = React.useState(true) - const [result, setResult] = React.useState(null) - const [error, setError] = React.useState(null) - - const makeRequest = () => { - method(...args) - .then((data) => { - setResult(data) - setLoading(false) - }) - .catch((err) => { - setError(err) - setLoading(false) - }) - } - - React.useEffect(() => { - makeRequest() - }, []) - - return [loading, result, error, makeRequest] - } - - async customRequest( - request = { - method: "GET", - }, - ...args - ) { - const instance = request.instance ?? this.instance.httpInterface - - if (!instance) { - throw new Error("No instance provided") - } - - // handle before request - await this.handleBeforeRequest(request) - - if (typeof request === "string") { - request = { - url: request, - } - } - - if (typeof request.headers !== "object") { - request.headers = {} - } - - let result = null - - const makeRequest = async () => { - const sessionToken = await SessionModel.token - - if (sessionToken) { - request.headers["Authorization"] = `Bearer ${sessionToken}` - } else { - console.warn("Making a request with no session token") - } - - const _result = await instance(request, ...args) - .catch((error) => { - return error - }) - - result = _result - } - - await makeRequest() - - // handle after request - await this.handleAfterRequest(result, makeRequest) - - // if error, throw it - if (result instanceof Error) { - throw result - } - - return result - } - - request(method, endpoint, ...args) { - return this.instance.endpoints[method][endpoint](...args) - } - - withEndpoints() { - return this.instance.endpoints - } - - handleBeforeRequest = async (request) => { - if (this.onExpiredExceptionEvent) { - if (this.excludedExpiredExceptionURL.includes(request.url)) return - - await new Promise((resolve) => { - app.eventBus.once("session.regenerated", () => { - console.log(`Session has been regenerated, retrying request`) - resolve() - }) - }) - } - } - - handleAfterRequest = async (data, callback) => { - // handle 401, 403 responses - if (data instanceof Error) { - if (data.code && (data.code === "ECONNABORTED" || data.code === "ERR_NETWORK")) { - console.error(`Request aborted or network error, ignoring`) - return false - } - - if (data.response.status === 401) { - // check if the server issue a refresh token on data - if (data.response.data.refreshToken) { - console.log(`Session expired, but the server issued a refresh token, handling regeneration event`) - - // handle regeneration event - await this.handleRegenerationEvent(data.response.data.refreshToken) - - return await callback() - } - - // check if route is from "session" namespace - if (data.config.url.includes("/session")) { - return window.app.eventBus.emit("session.invalid", "Session expired, but the server did not issue a refresh token") - } - } - - if (data.response.status === 403) { - if (data.config.url.includes("/session")) { - return window.app.eventBus.emit("session.invalid", "Session not valid or not existent") - } - } - } - } - - handleRegenerationEvent = async (refreshToken) => { - window.app.eventBus.emit("session.expiredExceptionEvent", refreshToken) - - this.onExpiredExceptionEvent = true - - const expiredToken = await SessionModel.token - - // send request to regenerate token - const response = await this.customRequest({ - method: "POST", - url: "/session/regenerate", - data: { - expiredToken: expiredToken, - refreshToken, - } - }).catch((error) => { - console.error(`Failed to regenerate token: ${error.message}`) - return false - }) - - if (!response) { - return window.app.eventBus.emit("session.invalid", "Failed to regenerate token") - } - - if (!response.data?.token) { - return window.app.eventBus.emit("session.invalid", "Failed to regenerate token, invalid server response.") - } - - // set new token - SessionModel.token = response.data.token - - //this.namespaces["main"].internalAbortController.abort() - - this.onExpiredExceptionEvent = false - - // emit event - window.app.eventBus.emit("session.regenerated") - } - - createBridge(params = {}) { - const getSessionContext = async () => { - const obj = {} - const token = await SessionModel.token - - if (token) { - // append token to context - obj.headers = { - Authorization: `Bearer ${token ?? null}`, - } - } - - return obj - } - - if (typeof params !== "object") { - throw new Error("Params must be an object") - } - - const bridgeOptions = { - wsOptions: { - autoConnect: false, - }, - onBeforeRequest: this.handleBeforeRequest, - onRequest: getSessionContext, - onResponse: this.handleAfterRequest, - ...params, - origin: params.httpAddress ?? config.remotes.mainApi, - } - - const bridge = new Bridge(bridgeOptions) - - // handle main ws onEvents - const mainSocket = bridge.wsInterface.sockets["main"] - - mainSocket.on("authenticated", () => { - console.debug("[WS] Authenticated") - }) - - mainSocket.on("authenticateFailed", (error) => { - console.error("[WS] Authenticate Failed", error) - }) - - mainSocket.on("connect", () => { - if (this.ctx.eventBus) { - this.ctx.eventBus.emit(`api.ws.main.connect`) - } - - console.debug("[WS] Connected, authenticating...") - - this.autenticateWS(mainSocket) - }) - - mainSocket.on("disconnect", (...context) => { - if (this.ctx.eventBus) { - this.ctx.eventBus.emit(`api.ws.main.disconnect`, ...context) - } - }) - - mainSocket.on("connect_error", (...context) => { - if (this.ctx.eventBus) { - this.ctx.eventBus.emit(`api.ws.main.connect_error`, ...context) - } - }) - - mainSocket.onAny((event, ...args) => { - console.debug(`[WS] Recived Event (${event})`, ...args) - }) - - // mainSocket.onAnyOutgoing((event, ...args) => { - // console.debug(`[WS] Sent Event (${event})`, ...args) - // }) - - return bridge - } - - listenEvent(event, callback) { - if (!this.instance.wsInterface) { - throw new Error("API is not attached") - } - - return this.instance.wsInterface.sockets["main"].on(event, callback) - } - - unlistenEvent(event, callback) { - if (!this.instance.wsInterface) { - throw new Error("API is not attached") - } - - return this.instance.wsInterface.sockets["main"].off(event, callback) - } - - async autenticateWS(socket) { - const token = await SessionModel.token - - if (!token) { - return console.error("Failed to authenticate WS, no token found") - } - - socket.emit("authenticate", { - token, - }) - } - - async measurePing() { - const timings = {} - - const promises = [ - new Promise(async (resolve) => { - const start = Date.now() - - this.customRequest({ - method: "GET", - url: "/ping", - }) - .then(() => { - // set http timing in ms - timings.http = Date.now() - start - - resolve() - }) - .catch(() => { - timings.http = "failed" - resolve() - }) - - setTimeout(() => { - timings.http = "failed" - - resolve() - }, 10000) - }), - new Promise((resolve) => { - const start = Date.now() - - this.instance.wsInterface.sockets["main"].on("pong", () => { - timings.ws = Date.now() - start - - resolve() - }) - - this.instance.wsInterface.sockets["main"].emit("ping") - - setTimeout(() => { - timings.ws = "failed" - - resolve() - }, 10000) - }) - ] - - await Promise.all(promises) - - return timings - } } \ No newline at end of file diff --git a/packages/app/src/models/auth/index.js b/packages/app/src/models/auth/index.js deleted file mode 100755 index 38a64e9e..00000000 --- a/packages/app/src/models/auth/index.js +++ /dev/null @@ -1,52 +0,0 @@ -import SessionModel from "../session" - -export default class AuthModel { - static login = async (payload) => { - const response = await app.cores.api.customRequest({ - method: "post", - url: "/auth/login", - data: { - username: payload.username, //window.btoa(payload.username), - password: payload.password, //window.btoa(payload.password), - }, - }) - - SessionModel.token = response.data.token - - app.eventBus.emit("auth:login_success") - - return response.data - } - - static logout = async () => { - await SessionModel.destroyCurrentSession() - - SessionModel.removeToken() - - app.eventBus.emit("auth:logout_success") - } - - static async register(payload) { - const { username, password, email } = payload - - const response = await app.cores.api.customRequest({ - method: "post", - url: "/auth/register", - data: { - username, - password, - email, - } - }).catch((error) => { - console.error(error) - - return false - }) - - if (!response) { - throw new Error("Unable to register user") - } - - return response - } -} \ No newline at end of file diff --git a/packages/app/src/models/feed/index.js b/packages/app/src/models/feed/index.js deleted file mode 100755 index 12a90f31..00000000 --- a/packages/app/src/models/feed/index.js +++ /dev/null @@ -1,79 +0,0 @@ -export default class FeedModel { - static async getMusicFeed({ trim, limit } = {}) { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/feed/music`, - params: { - trim: trim ?? 0, - limit: limit ?? window.app.cores.settings.get("feed_max_fetch"), - } - }) - - return data - } - - static async getGlobalMusicFeed({ trim, limit } = {}) { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/feed/music/global`, - params: { - trim: trim ?? 0, - limit: limit ?? window.app.cores.settings.get("feed_max_fetch"), - } - }) - - return data - } - - static async getTimelineFeed({ trim, limit } = {}) { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/feed/timeline`, - params: { - trim: trim ?? 0, - limit: limit ?? window.app.cores.settings.get("feed_max_fetch"), - } - }) - - return data - } - - static async getPostsFeed({ trim, limit } = {}) { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/feed/posts`, - params: { - trim: trim ?? 0, - limit: limit ?? window.app.cores.settings.get("feed_max_fetch"), - } - }) - - return data - } - - static async getPlaylistsFeed({ trim, limit } = {}) { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/feed/playlists`, - params: { - trim: trim ?? 0, - limit: limit ?? window.app.cores.settings.get("feed_max_fetch"), - } - }) - - return data - } - - static async search(keywords, params = {}) { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/search`, - params: { - keywords: keywords, - params: params - } - }) - - return data - } -} \ No newline at end of file diff --git a/packages/app/src/models/files/index.js b/packages/app/src/models/files/index.js deleted file mode 100755 index 06cd1acb..00000000 --- a/packages/app/src/models/files/index.js +++ /dev/null @@ -1,57 +0,0 @@ -export default class FilesModel { - static async uploadFile(file, ...args) { - const result = await app.cores.remoteStorage.uploadFile(file, ...args) - - return result - } - - static async deprecated_uploadFile(file) { - console.log("uploadFile", file) - - // get the file from the payload - if (!file) { - throw new Error("File is required") - } - - // create a new form data - const formData = new FormData() - - // append the file to the form data - formData.append("files", file) - - // send the request - const uploadRequest = await app.cores.api.customRequest({ - method: "POST", - url: "/files/upload", - data: formData, - }).catch((err) => { - throw new Error(err.response.data.message) - }) - - if (uploadRequest.data.files.length === 0) { - throw new Error("Upload failed, empty response") - } - - return uploadRequest.data.files[0] - } - - static async uploadFiles(files) { - // get the file from the payload - if (!files) { - throw new Error("Files are required") - } - - if (!Array.isArray(files)) { - throw new Error("Files must be an array") - } - - const resultFiles = [] - - for await (const file of files) { - const result = await FilesModel.uploadFile(file) - resultFiles.push(result) - } - - return resultFiles - } -} \ No newline at end of file diff --git a/packages/app/src/models/follows/index.js b/packages/app/src/models/follows/index.js deleted file mode 100755 index c3336cea..00000000 --- a/packages/app/src/models/follows/index.js +++ /dev/null @@ -1,47 +0,0 @@ -import { SessionModel } from "models" - -export default class FollowsModel { - static async imFollowing(user_id) { - if (!user_id) { - throw new Error("user_id is required") - } - - const response = await app.cores.api.customRequest( { - method: "GET", - url: `/follow/user/${user_id}`, - }) - - return response.data - } - - static async getFollowers(user_id) { - if (!user_id) { - // set current user_id - user_id = SessionModel.user_id - } - - const response = await app.cores.api.customRequest( { - method: "GET", - url: `/follow/user/${user_id}/followers`, - }) - - return response.data - } - - static async toogleFollow({ user_id, username }) { - if (!user_id && !username) { - throw new Error("user_id or username is required") - } - - const response = await app.cores.api.customRequest( { - method: "POST", - url: "/follow/user/toogle", - data: { - user_id: user_id, - username: username - }, - }) - - return response.data - } -} \ No newline at end of file diff --git a/packages/app/src/models/index.js b/packages/app/src/models/index.js deleted file mode 100755 index 15de7664..00000000 --- a/packages/app/src/models/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export { default as SessionModel } from "./session" -export { default as UserModel } from "./user" -export { default as FollowsModel } from "./follows" \ No newline at end of file diff --git a/packages/app/src/models/livestream/index.js b/packages/app/src/models/livestream/index.js deleted file mode 100755 index a6ee08ff..00000000 --- a/packages/app/src/models/livestream/index.js +++ /dev/null @@ -1,89 +0,0 @@ -import axios from "axios" -import config from "config" - -export default class Livestream { - static instance = axios.create({ - baseURL: config.remotes.livestreamingApi, - }) - - static async deleteProfile(profile_id) { - const request = await app.cores.api.customRequest({ - method: "DELETE", - url: `/tv/streaming/profile`, - data: { - profile_id - } - }) - - return request.data - } - - static async postProfile(payload) { - const request = await app.cores.api.customRequest({ - method: "POST", - url: `/tv/streaming/profile`, - data: payload, - }) - - return request.data - } - - static async getProfiles() { - const request = await app.cores.api.customRequest({ - method: "GET", - url: `/tv/streaming/profiles`, - }) - - return request.data - } - - static async regenerateStreamingKey(profile_id) { - const request = await app.cores.api.customRequest({ - method: "POST", - url: `/tv/streaming/regenerate_key`, - data: { - profile_id - } - }) - - return request.data - } - - static async getCategories(key) { - const request = await app.cores.api.customRequest({ - method: "GET", - url: `/tv/streaming/categories`, - params: { - key, - } - }) - - return request.data - } - - static async getLivestream(payload = {}) { - if (!payload.username) { - throw new Error("Username is required") - } - - let request = await app.cores.api.customRequest({ - method: "GET", - url: `/tv/streams`, - params: { - username: payload.username, - profile_id: payload.profile_id, - } - }) - - return request.data - } - - static async getLivestreams() { - const request = await app.cores.api.customRequest({ - method: "GET", - url: `/tv/streams`, - }) - - return request.data - } -} \ No newline at end of file diff --git a/packages/app/src/models/music/index.js b/packages/app/src/models/music/index.js deleted file mode 100755 index b6f3abb8..00000000 --- a/packages/app/src/models/music/index.js +++ /dev/null @@ -1,14 +0,0 @@ -export class MusicModel { - static get bridge() { - return window.app?.cores.api.withEndpoints() - } - - static async createSpaceRoom() { - const { data } = await app.cores.api.customRequest( { - method: "post", - url: `/music/create_space_room`, - }) - - return data - } -} \ No newline at end of file diff --git a/packages/app/src/models/playlists/index.js b/packages/app/src/models/playlists/index.js deleted file mode 100755 index a55f1849..00000000 --- a/packages/app/src/models/playlists/index.js +++ /dev/null @@ -1,46 +0,0 @@ -export default class PlaylistsModel { - static async putPlaylist(payload) { - if (!payload) { - throw new Error("Payload is required") - } - - const { data } = await app.cores.api.customRequest({ - method: "PUT", - url: `/playlist`, - data: payload, - }) - - return data - } - - static async getPlaylist(id) { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/playlist/data/${id}`, - }) - - return data - } - - static async getMyReleases() { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/playlist/self`, - }) - - return data - } - - static async deletePlaylist(id) { - if (!id) { - throw new Error("ID is required") - } - - const { data } = await app.cores.api.customRequest({ - method: "DELETE", - url: `/playlist/${id}`, - }) - - return data - } -} \ No newline at end of file diff --git a/packages/app/src/models/post/index.js b/packages/app/src/models/post/index.js deleted file mode 100755 index 9efa88a9..00000000 --- a/packages/app/src/models/post/index.js +++ /dev/null @@ -1,189 +0,0 @@ -export default class Post { - static get bridge() { - return window.app?.cores.api.withEndpoints() - } - - static get maxPostTextLength() { - return 3200 - } - - static get maxCommentLength() { - return 1200 - } - - static async getPost({ post_id }) { - if (!post_id) { - throw new Error("Post ID is required") - } - - const { data } = await app.cores.api.customRequest( { - method: "GET", - url: `/posts/post/${post_id}`, - }) - - return data - } - - static async getPostComments({ post_id }) { - if (!post_id) { - throw new Error("Post ID is required") - } - - const { data } = await app.cores.api.customRequest( { - method: "GET", - url: `/comments/post/${post_id}`, - }) - - return data - } - - static async sendComment({ post_id, comment }) { - if (!post_id || !comment) { - throw new Error("Post ID and/or comment are required") - } - - const request = await app.cores.api.customRequest( { - method: "POST", - url: `/comments/post/${post_id}`, - data: { - message: comment, - }, - }) - - return request - } - - static async deleteComment({ post_id, comment_id }) { - if (!post_id || !comment_id) { - throw new Error("Post ID and/or comment ID are required") - } - - const request = await app.cores.api.customRequest( { - method: "DELETE", - url: `/comments/post/${post_id}/${comment_id}`, - }) - - return request - } - - static async getExplorePosts({ trim, limit }) { - if (!Post.bridge) { - throw new Error("Bridge is not available") - } - - const { data } = await app.cores.api.customRequest( { - method: "GET", - url: `/posts/explore`, - params: { - trim: trim ?? 0, - limit: limit ?? window.app.cores.settings.get("feed_max_fetch"), - } - }) - - return data - } - - static async getSavedPosts({ trim, limit }) { - if (!Post.bridge) { - throw new Error("Bridge is not available") - } - - const { data } = await app.cores.api.customRequest( { - method: "GET", - url: `/posts/saved`, - params: { - trim: trim ?? 0, - limit: limit ?? window.app.cores.settings.get("feed_max_fetch"), - } - }) - - return data - } - - static async getUserPosts({ user_id, trim, limit }) { - if (!Post.bridge) { - throw new Error("Bridge is not available") - } - - if (!user_id) { - // use current user_id - user_id = app.userData?._id - } - - const { data } = await app.cores.api.customRequest( { - method: "GET", - url: `/posts/user/${user_id}`, - params: { - trim: trim ?? 0, - limit: limit ?? window.app.cores.settings.get("feed_max_fetch"), - } - }) - - return data - } - - static async toogleLike({ post_id }) { - if (!Post.bridge) { - throw new Error("Bridge is not available") - } - - if (!post_id) { - throw new Error("Post ID is required") - } - - const { data } = await app.cores.api.customRequest( { - method: "POST", - url: `/posts/${post_id}/toogle_like`, - }) - - return data - } - - static async toogleSave({ post_id }) { - if (!Post.bridge) { - throw new Error("Bridge is not available") - } - - if (!post_id) { - throw new Error("Post ID is required") - } - - const { data } = await app.cores.api.customRequest( { - method: "POST", - url: `/posts/${post_id}/toogle_save`, - }) - - return data - } - - static async create(payload) { - if (!Post.bridge) { - throw new Error("Bridge is not available") - } - - const { data } = await app.cores.api.customRequest( { - method: "POST", - url: `/posts/new`, - data: payload, - }) - - return data - } - - static async deletePost({ post_id }) { - if (!Post.bridge) { - throw new Error("Bridge is not available") - } - - if (!post_id) { - throw new Error("Post ID is required") - } - - const { data } = await app.cores.api.customRequest( { - method: "DELETE", - url: `/posts/${post_id}`, - }) - - return data - } -} \ No newline at end of file diff --git a/packages/app/src/models/session/index.js b/packages/app/src/models/session/index.js deleted file mode 100755 index e361aece..00000000 --- a/packages/app/src/models/session/index.js +++ /dev/null @@ -1,114 +0,0 @@ -import cookies from "js-cookie" -import jwt_decode from "jwt-decode" -import config from "config" - -export default class Session { - static storageTokenKey = config.app?.storage?.token ?? "token" - - static get token() { - return cookies.get(this.storageTokenKey) - } - - static set token(token) { - return cookies.set(this.storageTokenKey, token) - } - - static get user_id() { - return this.getDecodedToken()?.user_id - } - - static get session_uuid() { - return this.getDecodedToken()?.session_uuid - } - - static getDecodedToken() { - const token = this.token - - return token && jwt_decode(token) - } - - static async getAllSessions() { - const response = await app.cores.api.customRequest({ - method: "get", - url: "/session/all" - }) - - return response.data - } - - static async getCurrentSession() { - const response = await app.cores.api.customRequest({ - method: "get", - url: "/session/current" - }) - - return response.data - } - - static async getTokenValidation() { - const session = await Session.token - - const response = await app.cores.api.customRequest({ - method: "get", - url: "/session/validate", - data: { - session: session - } - }) - - return response.data - } - - static removeToken() { - return cookies.remove(Session.storageTokenKey) - } - - static async destroyCurrentSession() { - const token = await Session.token - const session = await Session.getDecodedToken() - - if (!session || !token) { - return false - } - - const response = await app.cores.api.customRequest({ - method: "delete", - url: "/session/current" - }).catch((error) => { - console.error(error) - - return false - }) - - Session.removeToken() - - window.app.eventBus.emit("session.destroyed") - - return response.data - } - - static async destroyAllSessions() { - const session = await Session.getDecodedToken() - - if (!session) { - return false - } - - const response = await app.cores.api.customRequest({ - method: "delete", - url: "/session/all" - }) - - Session.removeToken() - - window.app.eventBus.emit("session.destroyed") - - return response.data - } - - static async isCurrentTokenValid() { - const health = await Session.getTokenValidation() - - return health.valid - } -} \ No newline at end of file diff --git a/packages/app/src/models/sync/cores/spotifyCore.js b/packages/app/src/models/sync/cores/spotifyCore.js deleted file mode 100755 index 82fb2d74..00000000 --- a/packages/app/src/models/sync/cores/spotifyCore.js +++ /dev/null @@ -1,87 +0,0 @@ -export default class SpotifySyncModel { - static get spotify_redirect_uri() { - return window.location.origin + "/callbacks/sync/spotify" - } - - static get spotify_authorize_endpoint() { - return "https://accounts.spotify.com/authorize?response_type=code&client_id={{client_id}}&scope={{scope}}&redirect_uri={{redirect_uri}}&response_type=code" - } - - static async authorizeAccount() { - const scopes = [ - "user-read-private", - "user-modify-playback-state", - "user-read-currently-playing", - "user-read-playback-state", - "streaming", - ] - - const { client_id } = await SpotifySyncModel.get_client_id() - - const parsedUrl = SpotifySyncModel.spotify_authorize_endpoint - .replace("{{client_id}}", client_id) - .replace("{{scope}}", scopes.join(" ")) - .replace("{{redirect_uri}}", SpotifySyncModel.spotify_redirect_uri) - - // open on a new tab - window.open(parsedUrl, "_blank") - } - - static async get_client_id() { - const { data } = await app.cores.api.customRequest( { - method: "GET", - url: `/sync/spotify/client_id`, - }) - - return data - } - - static async syncAuthCode(code) { - const { data } = await app.cores.api.customRequest( { - method: "POST", - url: `/sync/spotify/auth`, - data: { - redirect_uri: SpotifySyncModel.spotify_redirect_uri, - code, - }, - }) - - return data - } - - static async unlinkAccount() { - const { data } = await app.cores.api.customRequest( { - method: "POST", - url: `/sync/spotify/unlink`, - }) - - return data - } - - static async isAuthorized() { - const { data } = await app.cores.api.customRequest( { - method: "GET", - url: `/sync/spotify/is_authorized`, - }) - - return data - } - - static async getData() { - const { data } = await app.cores.api.customRequest( { - method: "GET", - url: `/sync/spotify/data`, - }) - - return data - } - - static async getCurrentPlaying() { - const { data } = await app.cores.api.customRequest( { - method: "GET", - url: `/sync/spotify/currently_playing`, - }) - - return data - } -} \ No newline at end of file diff --git a/packages/app/src/models/sync/index.js b/packages/app/src/models/sync/index.js deleted file mode 100755 index 43bcbf0c..00000000 --- a/packages/app/src/models/sync/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import SpotifySyncModel from "./cores/spotifyCore" - -export default class SyncModel { - static get bridge() { - return window.app?.cores.api.withEndpoints() - } - - static get spotifyCore() { - return SpotifySyncModel - } -} \ No newline at end of file diff --git a/packages/app/src/models/user/index.js b/packages/app/src/models/user/index.js deleted file mode 100755 index 36a750d8..00000000 --- a/packages/app/src/models/user/index.js +++ /dev/null @@ -1,158 +0,0 @@ -import SessionModel from "../session" - -export default class User { - static async data(payload = {}) { - let { - username, - user_id, - } = payload - - if (!username && !user_id) { - user_id = SessionModel.user_id - } - - if (username && !user_id) { - // resolve user_id from username - const resolveResponse = await app.cores.api.customRequest({ - method: "GET", - url: `/user/user_id/${username}`, - }) - - user_id = resolveResponse.data.user_id - } - - const response = await app.cores.api.customRequest({ - method: "GET", - url: `/user/${user_id}/data`, - }) - - return response.data - } - - static async updateData(payload) { - const response = await app.cores.api.customRequest({ - method: "POST", - url: "/user/self/update_data", - data: { - update: payload, - }, - }) - - return response.data - } - - static async unsetFullName() { - const response = await app.cores.api.customRequest({ - method: "DELETE", - url: "/user/self/public_name", - }) - - return response.data - } - - static async selfRoles() { - const response = await app.cores.api.customRequest({ - method: "GET", - url: "/roles/self", - }) - - return response.data - } - - static async haveRole(role) { - const roles = await User.selfRoles() - - if (!roles) { - return false - } - - return Array.isArray(roles) && roles.includes(role) - } - - static async haveAdmin() { - return User.haveRole("admin") - } - - static async getUserBadges(user_id) { - if (!user_id) { - user_id = SessionModel.user_id - } - - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/badge/user/${user_id}`, - }) - - return data - } - - static async changePassword(payload) { - const { currentPassword, newPassword } = payload - - const { data } = await app.cores.api.customRequest({ - method: "POST", - url: "/self/update_password", - data: { - currentPassword, - newPassword, - } - }) - - return data - } - - static async getUserFollowers({ - user_id, - limit = 20, - offset = 0, - }) { - // if user_id or username is not provided, set with current user - if (!user_id && !username) { - user_id = SessionModel.user_id - } - - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/user/${user_id}/followers`, - params: { - limit, - offset, - } - }) - - return data - } - - static async getConnectedUsersFollowing() { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: "/status/connected/following", - }) - - return data - } - - static async checkUsernameAvailability(username) { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/user/username_available`, - params: { - username, - } - }) - - return data - } - - static async checkEmailAvailability(email) { - const { data } = await app.cores.api.customRequest({ - method: "GET", - url: `/user/email_available`, - params: { - email, - } - }) - - return data - } -} \ No newline at end of file diff --git a/packages/app/src/pages/account/index.jsx b/packages/app/src/pages/account/index.jsx index 1347dd64..9b5c191c 100755 --- a/packages/app/src/pages/account/index.jsx +++ b/packages/app/src/pages/account/index.jsx @@ -74,8 +74,6 @@ export default class Account extends React.Component { actionsRef = React.createRef() - api = window.app.cores.api.withEndpoints() - componentDidMount = async () => { const token = await SessionModel.getDecodedToken() const location = window.app.history.location diff --git a/packages/app/src/pages/music/creator/index.jsx b/packages/app/src/pages/music/creator/index.jsx index 23b09169..dab16f75 100755 --- a/packages/app/src/pages/music/creator/index.jsx +++ b/packages/app/src/pages/music/creator/index.jsx @@ -3,7 +3,6 @@ import * as antd from "antd" import jsmediatags from "jsmediatags/dist/jsmediatags.min.js" import PlaylistModel from "models/playlists" -import FilesModel from "models/files" import BasicInformation from "./components/BasicInformation" import TracksUploads from "./components/TracksUploads" @@ -105,7 +104,7 @@ export default class PlaylistCreatorSteps extends React.Component { } handleUploadTrack = async (req) => { - const response = await FilesModel.uploadFile(req.file, { + const response = await app.cores.remoteStorage.uploadFile(req.file, { timeout: 2000 }).catch((error) => { console.error(error) @@ -184,7 +183,7 @@ export default class PlaylistCreatorSteps extends React.Component { } // upload cover file - const result = await FilesModel.uploadFile(file, { + const result = await app.cores.remoteStorage.uploadFile(file, { timeout: 2000 })