mirror of
https://github.com/20kaushik02/spotify-manager.git
synced 2026-01-25 06:04:05 +00:00
bugfixes, improving API request wrapper
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import dotenvFlow from "dotenv-flow";
|
import _ from "./config/dotenv.ts";
|
||||||
dotenvFlow.config();
|
|
||||||
|
|
||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { axiosInstance } from "./axios.ts";
|
import { axiosInstance } from "./axios.ts";
|
||||||
|
|
||||||
import { type AxiosResponse, type AxiosRequestConfig } from "axios";
|
import {
|
||||||
|
type AxiosResponse,
|
||||||
|
type AxiosRequestConfig,
|
||||||
|
type RawAxiosRequestHeaders,
|
||||||
|
} from "axios";
|
||||||
import type {
|
import type {
|
||||||
AddItemsToPlaylist,
|
AddItemsToPlaylist,
|
||||||
EndpointHandlerBaseArgs,
|
EndpointHandlerBaseArgs,
|
||||||
@@ -9,7 +13,6 @@ import type {
|
|||||||
GetPlaylist,
|
GetPlaylist,
|
||||||
GetPlaylistItems,
|
GetPlaylistItems,
|
||||||
RemovePlaylistItems,
|
RemovePlaylistItems,
|
||||||
Req,
|
|
||||||
Res,
|
Res,
|
||||||
} from "spotify_manager/index.d.ts";
|
} from "spotify_manager/index.d.ts";
|
||||||
|
|
||||||
@@ -34,7 +37,7 @@ enum allowedMethods {
|
|||||||
* @param inlineData true if `data` is to be placed inside config (say, axios' delete method)
|
* @param inlineData true if `data` is to be placed inside config (say, axios' delete method)
|
||||||
*/
|
*/
|
||||||
const singleRequest = async <RespDataType>(
|
const singleRequest = async <RespDataType>(
|
||||||
req: Req,
|
authHeaders: RawAxiosRequestHeaders,
|
||||||
res: Res,
|
res: Res,
|
||||||
method: allowedMethods,
|
method: allowedMethods,
|
||||||
path: string,
|
path: string,
|
||||||
@@ -43,7 +46,7 @@ const singleRequest = async <RespDataType>(
|
|||||||
inlineData: boolean = false
|
inlineData: boolean = false
|
||||||
): Promise<AxiosResponse<RespDataType, any> | null> => {
|
): Promise<AxiosResponse<RespDataType, any> | null> => {
|
||||||
let resp: AxiosResponse<RespDataType, any>;
|
let resp: AxiosResponse<RespDataType, any>;
|
||||||
config.headers = { ...config.headers, ...req.session.authHeaders };
|
config.headers = { ...config.headers, ...authHeaders };
|
||||||
try {
|
try {
|
||||||
if (!data || inlineData) {
|
if (!data || inlineData) {
|
||||||
if (data) config.data = data ?? null;
|
if (data) config.data = data ?? null;
|
||||||
@@ -87,15 +90,12 @@ const singleRequest = async <RespDataType>(
|
|||||||
interface GetCurrentUsersProfileArgs extends EndpointHandlerBaseArgs {}
|
interface GetCurrentUsersProfileArgs extends EndpointHandlerBaseArgs {}
|
||||||
const getCurrentUsersProfile: (
|
const getCurrentUsersProfile: (
|
||||||
opts: GetCurrentUsersProfileArgs
|
opts: GetCurrentUsersProfileArgs
|
||||||
) => Promise<GetCurrentUsersProfile | null> = async ({ req, res }) => {
|
) => Promise<GetCurrentUsersProfile | null> = async ({ authHeaders, res }) => {
|
||||||
const response = await singleRequest<GetCurrentUsersProfile>(
|
const response = await singleRequest<GetCurrentUsersProfile>(
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
allowedMethods.Get,
|
allowedMethods.Get,
|
||||||
"/me",
|
"/me"
|
||||||
{
|
|
||||||
headers: { Authorization: `Bearer ${req.session.accessToken}` },
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
return response ? response.data : null;
|
return response ? response.data : null;
|
||||||
};
|
};
|
||||||
@@ -104,9 +104,12 @@ interface GetCurrentUsersPlaylistsFirstPageArgs
|
|||||||
extends EndpointHandlerBaseArgs {}
|
extends EndpointHandlerBaseArgs {}
|
||||||
const getCurrentUsersPlaylistsFirstPage: (
|
const getCurrentUsersPlaylistsFirstPage: (
|
||||||
opts: GetCurrentUsersPlaylistsFirstPageArgs
|
opts: GetCurrentUsersPlaylistsFirstPageArgs
|
||||||
) => Promise<GetCurrentUsersPlaylists | null> = async ({ req, res }) => {
|
) => Promise<GetCurrentUsersPlaylists | null> = async ({
|
||||||
|
authHeaders,
|
||||||
|
res,
|
||||||
|
}) => {
|
||||||
const response = await singleRequest<GetCurrentUsersPlaylists>(
|
const response = await singleRequest<GetCurrentUsersPlaylists>(
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
allowedMethods.Get,
|
allowedMethods.Get,
|
||||||
`/me/playlists`,
|
`/me/playlists`,
|
||||||
@@ -126,12 +129,12 @@ interface GetCurrentUsersPlaylistsNextPageArgs extends EndpointHandlerBaseArgs {
|
|||||||
const getCurrentUsersPlaylistsNextPage: (
|
const getCurrentUsersPlaylistsNextPage: (
|
||||||
opts: GetCurrentUsersPlaylistsNextPageArgs
|
opts: GetCurrentUsersPlaylistsNextPageArgs
|
||||||
) => Promise<GetCurrentUsersPlaylists | null> = async ({
|
) => Promise<GetCurrentUsersPlaylists | null> = async ({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
nextURL,
|
nextURL,
|
||||||
}) => {
|
}) => {
|
||||||
const response = await singleRequest<GetCurrentUsersPlaylists>(
|
const response = await singleRequest<GetCurrentUsersPlaylists>(
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
allowedMethods.Get,
|
allowedMethods.Get,
|
||||||
nextURL
|
nextURL
|
||||||
@@ -146,13 +149,13 @@ interface GetPlaylistDetailsFirstPageArgs extends EndpointHandlerBaseArgs {
|
|||||||
const getPlaylistDetailsFirstPage: (
|
const getPlaylistDetailsFirstPage: (
|
||||||
opts: GetPlaylistDetailsFirstPageArgs
|
opts: GetPlaylistDetailsFirstPageArgs
|
||||||
) => Promise<GetPlaylist | null> = async ({
|
) => Promise<GetPlaylist | null> = async ({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
initialFields,
|
initialFields,
|
||||||
playlistID,
|
playlistID,
|
||||||
}) => {
|
}) => {
|
||||||
const response = await singleRequest<GetPlaylist>(
|
const response = await singleRequest<GetPlaylist>(
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
allowedMethods.Get,
|
allowedMethods.Get,
|
||||||
`/playlists/${playlistID}/`,
|
`/playlists/${playlistID}/`,
|
||||||
@@ -170,9 +173,13 @@ interface GetPlaylistDetailsNextPageArgs extends EndpointHandlerBaseArgs {
|
|||||||
}
|
}
|
||||||
const getPlaylistDetailsNextPage: (
|
const getPlaylistDetailsNextPage: (
|
||||||
opts: GetPlaylistDetailsNextPageArgs
|
opts: GetPlaylistDetailsNextPageArgs
|
||||||
) => Promise<GetPlaylistItems | null> = async ({ req, res, nextURL }) => {
|
) => Promise<GetPlaylistItems | null> = async ({
|
||||||
|
authHeaders,
|
||||||
|
res,
|
||||||
|
nextURL,
|
||||||
|
}) => {
|
||||||
const response = await singleRequest<GetPlaylistItems>(
|
const response = await singleRequest<GetPlaylistItems>(
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
allowedMethods.Get,
|
allowedMethods.Get,
|
||||||
nextURL
|
nextURL
|
||||||
@@ -187,13 +194,13 @@ interface AddItemsToPlaylistArgs extends EndpointHandlerBaseArgs {
|
|||||||
const addItemsToPlaylist: (
|
const addItemsToPlaylist: (
|
||||||
opts: AddItemsToPlaylistArgs
|
opts: AddItemsToPlaylistArgs
|
||||||
) => Promise<AddItemsToPlaylist | null> = async ({
|
) => Promise<AddItemsToPlaylist | null> = async ({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
nextBatch,
|
nextBatch,
|
||||||
playlistID,
|
playlistID,
|
||||||
}) => {
|
}) => {
|
||||||
const response = await singleRequest<AddItemsToPlaylist>(
|
const response = await singleRequest<AddItemsToPlaylist>(
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
allowedMethods.Post,
|
allowedMethods.Post,
|
||||||
`/playlists/${playlistID}/tracks`,
|
`/playlists/${playlistID}/tracks`,
|
||||||
@@ -212,7 +219,7 @@ interface RemovePlaylistItemsArgs extends EndpointHandlerBaseArgs {
|
|||||||
const removePlaylistItems: (
|
const removePlaylistItems: (
|
||||||
opts: RemovePlaylistItemsArgs
|
opts: RemovePlaylistItemsArgs
|
||||||
) => Promise<RemovePlaylistItems | null> = async ({
|
) => Promise<RemovePlaylistItems | null> = async ({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
nextBatch,
|
nextBatch,
|
||||||
playlistID,
|
playlistID,
|
||||||
@@ -221,7 +228,7 @@ const removePlaylistItems: (
|
|||||||
// API doesn't document this kind of deletion via the 'positions' field
|
// API doesn't document this kind of deletion via the 'positions' field
|
||||||
// but see here: https://github.com/spotipy-dev/spotipy/issues/95#issuecomment-2263634801
|
// but see here: https://github.com/spotipy-dev/spotipy/issues/95#issuecomment-2263634801
|
||||||
const response = await singleRequest<RemovePlaylistItems>(
|
const response = await singleRequest<RemovePlaylistItems>(
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
allowedMethods.Delete,
|
allowedMethods.Delete,
|
||||||
`/playlists/${playlistID}/tracks`,
|
`/playlists/${playlistID}/tracks`,
|
||||||
@@ -243,11 +250,11 @@ interface CheckPlaylistEditableArgs extends EndpointHandlerBaseArgs {
|
|||||||
}
|
}
|
||||||
const checkPlaylistEditable: (
|
const checkPlaylistEditable: (
|
||||||
opts: CheckPlaylistEditableArgs
|
opts: CheckPlaylistEditableArgs
|
||||||
) => Promise<boolean> = async ({ req, res, playlistID, userID }) => {
|
) => Promise<boolean> = async ({ authHeaders, res, playlistID, userID }) => {
|
||||||
let checkFields = ["collaborative", "owner(id)"];
|
let checkFields = ["collaborative", "owner(id)"];
|
||||||
|
|
||||||
const checkFromData = await getPlaylistDetailsFirstPage({
|
const checkFromData = await getPlaylistDetailsFirstPage({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
initialFields: checkFields.join(),
|
initialFields: checkFields.join(),
|
||||||
playlistID,
|
playlistID,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { RequestHandler } from "express";
|
import type { RequestHandler } from "express";
|
||||||
|
|
||||||
import curriedLogger from "../utils/logger.ts";
|
import logger from "../utils/logger.ts";
|
||||||
const logger = curriedLogger(import.meta.filename);
|
|
||||||
|
|
||||||
const __controller_func: RequestHandler = async (req, res) => {
|
const __controller_func: RequestHandler = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ const callback: RequestHandler = async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const { code, state, error } = req.query;
|
const { code, state, error } = req.query;
|
||||||
const storedState = req.cookies ? req.cookies[stateKey] : null;
|
const storedState = req.cookies ? req.cookies[stateKey] : null;
|
||||||
|
let authHeaders;
|
||||||
|
|
||||||
// check state
|
// check state
|
||||||
if (state === null || state !== storedState) {
|
if (state === null || state !== storedState) {
|
||||||
@@ -76,14 +77,18 @@ const callback: RequestHandler = async (req, res) => {
|
|||||||
logger.debug("Tokens obtained.");
|
logger.debug("Tokens obtained.");
|
||||||
req.session.accessToken = tokenResponse.data.access_token;
|
req.session.accessToken = tokenResponse.data.access_token;
|
||||||
req.session.refreshToken = tokenResponse.data.refresh_token;
|
req.session.refreshToken = tokenResponse.data.refresh_token;
|
||||||
|
authHeaders = {
|
||||||
|
Authorization: `Bearer ${req.session.accessToken}`,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
logger.error("login failed", { statusCode: tokenResponse.status });
|
logger.error("login failed", { statusCode: tokenResponse.status });
|
||||||
res
|
res
|
||||||
.status(tokenResponse.status)
|
.status(tokenResponse.status)
|
||||||
.send({ message: "Error: Login failed" });
|
.send({ message: "Error: Login failed" });
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userData = await getCurrentUsersProfile({ req, res });
|
const userData = await getCurrentUsersProfile({ authHeaders, res });
|
||||||
if (!userData) return null;
|
if (!userData) return null;
|
||||||
|
|
||||||
req.session.user = {
|
req.session.user = {
|
||||||
|
|||||||
@@ -37,13 +37,20 @@ import logger from "../utils/logger.ts";
|
|||||||
*/
|
*/
|
||||||
const updateUser: RequestHandler = async (req, res) => {
|
const updateUser: RequestHandler = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
let currentPlaylists: PlaylistModel_Pl[] = [];
|
|
||||||
if (!req.session.user)
|
if (!req.session.user)
|
||||||
throw new ReferenceError("sessionData does not have user object");
|
throw new ReferenceError("session does not have user object");
|
||||||
|
const { authHeaders } = req.session;
|
||||||
|
if (!authHeaders)
|
||||||
|
throw new ReferenceError("session does not have auth headers");
|
||||||
const uID = req.session.user.id;
|
const uID = req.session.user.id;
|
||||||
|
|
||||||
|
let currentPlaylists: PlaylistModel_Pl[] = [];
|
||||||
|
|
||||||
// get first 50
|
// get first 50
|
||||||
const respData = await getCurrentUsersPlaylistsFirstPage({ req, res });
|
const respData = await getCurrentUsersPlaylistsFirstPage({
|
||||||
|
authHeaders,
|
||||||
|
res,
|
||||||
|
});
|
||||||
if (!respData) return null;
|
if (!respData) return null;
|
||||||
|
|
||||||
currentPlaylists = respData.items.map((playlist) => {
|
currentPlaylists = respData.items.map((playlist) => {
|
||||||
@@ -57,7 +64,7 @@ const updateUser: RequestHandler = async (req, res) => {
|
|||||||
// keep getting batches of 50 till exhausted
|
// keep getting batches of 50 till exhausted
|
||||||
while (nextURL) {
|
while (nextURL) {
|
||||||
const nextData = await getCurrentUsersPlaylistsNextPage({
|
const nextData = await getCurrentUsersPlaylistsNextPage({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
nextURL,
|
nextURL,
|
||||||
});
|
});
|
||||||
@@ -217,7 +224,7 @@ const fetchUser: RequestHandler = async (req, res) => {
|
|||||||
// return null;
|
// return null;
|
||||||
// }
|
// }
|
||||||
if (!req.session.user)
|
if (!req.session.user)
|
||||||
throw new ReferenceError("sessionData does not have user object");
|
throw new ReferenceError("session does not have user object");
|
||||||
const uID = req.session.user.id;
|
const uID = req.session.user.id;
|
||||||
|
|
||||||
const currentPlaylists = await Playlists.findAll({
|
const currentPlaylists = await Playlists.findAll({
|
||||||
@@ -259,7 +266,7 @@ const createLink: RequestHandler = async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
// await sleep(1000);
|
// await sleep(1000);
|
||||||
if (!req.session.user)
|
if (!req.session.user)
|
||||||
throw new ReferenceError("sessionData does not have user object");
|
throw new ReferenceError("session does not have user object");
|
||||||
const uID = req.session.user.id;
|
const uID = req.session.user.id;
|
||||||
|
|
||||||
let fromPl, toPl;
|
let fromPl, toPl;
|
||||||
@@ -351,7 +358,7 @@ const createLink: RequestHandler = async (req, res) => {
|
|||||||
const removeLink: RequestHandler = async (req, res) => {
|
const removeLink: RequestHandler = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
if (!req.session.user)
|
if (!req.session.user)
|
||||||
throw new Error("sessionData does not have user object");
|
throw new ReferenceError("session does not have user object");
|
||||||
const uID = req.session.user.id;
|
const uID = req.session.user.id;
|
||||||
|
|
||||||
let fromPl, toPl;
|
let fromPl, toPl;
|
||||||
@@ -416,12 +423,16 @@ interface _GetPlaylistTracks {
|
|||||||
}
|
}
|
||||||
const _getPlaylistTracks: (
|
const _getPlaylistTracks: (
|
||||||
opts: _GetPlaylistTracksArgs
|
opts: _GetPlaylistTracksArgs
|
||||||
) => Promise<_GetPlaylistTracks | null> = async ({ req, res, playlistID }) => {
|
) => Promise<_GetPlaylistTracks | null> = async ({
|
||||||
|
authHeaders,
|
||||||
|
res,
|
||||||
|
playlistID,
|
||||||
|
}) => {
|
||||||
let initialFields = ["snapshot_id,tracks(next,items(is_local,track(uri)))"];
|
let initialFields = ["snapshot_id,tracks(next,items(is_local,track(uri)))"];
|
||||||
let mainFields = ["next", "items(is_local,track(uri))"];
|
let mainFields = ["next", "items(is_local,track(uri))"];
|
||||||
|
|
||||||
const respData = await getPlaylistDetailsFirstPage({
|
const respData = await getPlaylistDetailsFirstPage({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
initialFields: initialFields.join(),
|
initialFields: initialFields.join(),
|
||||||
playlistID,
|
playlistID,
|
||||||
@@ -460,7 +471,7 @@ const _getPlaylistTracks: (
|
|||||||
// keep getting batches of 50 till exhausted
|
// keep getting batches of 50 till exhausted
|
||||||
while (nextURL) {
|
while (nextURL) {
|
||||||
const nextData = await getPlaylistDetailsNextPage({
|
const nextData = await getPlaylistDetailsNextPage({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
nextURL,
|
nextURL,
|
||||||
});
|
});
|
||||||
@@ -514,7 +525,7 @@ interface _PopulateSingleLinkCoreArgs extends EndpointHandlerBaseArgs {
|
|||||||
const _populateSingleLinkCore: (
|
const _populateSingleLinkCore: (
|
||||||
opts: _PopulateSingleLinkCoreArgs
|
opts: _PopulateSingleLinkCoreArgs
|
||||||
) => Promise<{ toAddNum: number; localNum: number } | null> = async ({
|
) => Promise<{ toAddNum: number; localNum: number } | null> = async ({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
link,
|
link,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -523,12 +534,12 @@ const _populateSingleLinkCore: (
|
|||||||
toPl = link.to;
|
toPl = link.to;
|
||||||
|
|
||||||
const fromPlaylist = await _getPlaylistTracks({
|
const fromPlaylist = await _getPlaylistTracks({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
playlistID: fromPl.id,
|
playlistID: fromPl.id,
|
||||||
});
|
});
|
||||||
const toPlaylist = await _getPlaylistTracks({
|
const toPlaylist = await _getPlaylistTracks({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
playlistID: toPl.id,
|
playlistID: toPl.id,
|
||||||
});
|
});
|
||||||
@@ -547,7 +558,7 @@ const _populateSingleLinkCore: (
|
|||||||
while (toTrackURIs.length > 0) {
|
while (toTrackURIs.length > 0) {
|
||||||
const nextBatch = toTrackURIs.splice(0, 100);
|
const nextBatch = toTrackURIs.splice(0, 100);
|
||||||
const addData = await addItemsToPlaylist({
|
const addData = await addItemsToPlaylist({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
nextBatch,
|
nextBatch,
|
||||||
playlistID: fromPl.id,
|
playlistID: fromPl.id,
|
||||||
@@ -566,8 +577,11 @@ const _populateSingleLinkCore: (
|
|||||||
const populateSingleLink: RequestHandler = async (req, res) => {
|
const populateSingleLink: RequestHandler = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
if (!req.session.user)
|
if (!req.session.user)
|
||||||
throw new Error("sessionData does not have user object");
|
throw new ReferenceError("session does not have user object");
|
||||||
const uID = req.session.user.id;
|
const uID = req.session.user.id;
|
||||||
|
const { authHeaders } = req.session;
|
||||||
|
if (!authHeaders)
|
||||||
|
throw new ReferenceError("session does not have auth headers");
|
||||||
const link = { from: req.body.from, to: req.body.to };
|
const link = { from: req.body.from, to: req.body.to };
|
||||||
let fromPl, toPl;
|
let fromPl, toPl;
|
||||||
|
|
||||||
@@ -599,7 +613,7 @@ const populateSingleLink: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
!(await checkPlaylistEditable({
|
!(await checkPlaylistEditable({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
playlistID: fromPl.id,
|
playlistID: fromPl.id,
|
||||||
userID: uID,
|
userID: uID,
|
||||||
@@ -608,7 +622,7 @@ const populateSingleLink: RequestHandler = async (req, res) => {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
const result = await _populateSingleLinkCore({
|
const result = await _populateSingleLinkCore({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
link: { from: fromPl, to: toPl },
|
link: { from: fromPl, to: toPl },
|
||||||
});
|
});
|
||||||
@@ -651,18 +665,22 @@ interface _PruneSingleLinkCoreArgs extends EndpointHandlerBaseArgs {
|
|||||||
*/
|
*/
|
||||||
const _pruneSingleLinkCore: (
|
const _pruneSingleLinkCore: (
|
||||||
opts: _PruneSingleLinkCoreArgs
|
opts: _PruneSingleLinkCoreArgs
|
||||||
) => Promise<{ toDelNum: number } | null> = async ({ req, res, link }) => {
|
) => Promise<{ toDelNum: number } | null> = async ({
|
||||||
|
authHeaders,
|
||||||
|
res,
|
||||||
|
link,
|
||||||
|
}) => {
|
||||||
try {
|
try {
|
||||||
const fromPl = link.from,
|
const fromPl = link.from,
|
||||||
toPl = link.to;
|
toPl = link.to;
|
||||||
|
|
||||||
const fromPlaylist = await _getPlaylistTracks({
|
const fromPlaylist = await _getPlaylistTracks({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
playlistID: fromPl.id,
|
playlistID: fromPl.id,
|
||||||
});
|
});
|
||||||
const toPlaylist = await _getPlaylistTracks({
|
const toPlaylist = await _getPlaylistTracks({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
playlistID: toPl.id,
|
playlistID: toPl.id,
|
||||||
});
|
});
|
||||||
@@ -684,7 +702,7 @@ const _pruneSingleLinkCore: (
|
|||||||
while (indexes.length > 0) {
|
while (indexes.length > 0) {
|
||||||
const nextBatch = indexes.splice(Math.max(indexes.length - 100, 0), 100);
|
const nextBatch = indexes.splice(Math.max(indexes.length - 100, 0), 100);
|
||||||
const delResponse = await removePlaylistItems({
|
const delResponse = await removePlaylistItems({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
nextBatch,
|
nextBatch,
|
||||||
playlistID: toPl.id,
|
playlistID: toPl.id,
|
||||||
@@ -705,8 +723,11 @@ const _pruneSingleLinkCore: (
|
|||||||
const pruneSingleLink: RequestHandler = async (req, res) => {
|
const pruneSingleLink: RequestHandler = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
if (!req.session.user)
|
if (!req.session.user)
|
||||||
throw new Error("sessionData does not have user object");
|
throw new ReferenceError("session does not have user object");
|
||||||
const uID = req.session.user.id;
|
const uID = req.session.user.id;
|
||||||
|
const { authHeaders } = req.session;
|
||||||
|
if (!authHeaders)
|
||||||
|
throw new ReferenceError("session does not have auth headers");
|
||||||
const link = { from: req.body.from, to: req.body.to };
|
const link = { from: req.body.from, to: req.body.to };
|
||||||
|
|
||||||
let fromPl, toPl;
|
let fromPl, toPl;
|
||||||
@@ -738,7 +759,7 @@ const pruneSingleLink: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
!(await checkPlaylistEditable({
|
!(await checkPlaylistEditable({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
playlistID: toPl.id,
|
playlistID: toPl.id,
|
||||||
userID: uID,
|
userID: uID,
|
||||||
@@ -747,7 +768,7 @@ const pruneSingleLink: RequestHandler = async (req, res) => {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
const result = await _pruneSingleLinkCore({
|
const result = await _pruneSingleLinkCore({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
link: {
|
link: {
|
||||||
from: fromPl,
|
from: fromPl,
|
||||||
|
|||||||
@@ -16,8 +16,14 @@ import logger from "../utils/logger.ts";
|
|||||||
*/
|
*/
|
||||||
const fetchUserPlaylists: RequestHandler = async (req, res) => {
|
const fetchUserPlaylists: RequestHandler = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
const { authHeaders } = req.session;
|
||||||
|
if (!authHeaders)
|
||||||
|
throw new ReferenceError("session does not have auth headers");
|
||||||
// get first 50
|
// get first 50
|
||||||
const respData = await getCurrentUsersPlaylistsFirstPage({ req, res });
|
const respData = await getCurrentUsersPlaylistsFirstPage({
|
||||||
|
authHeaders,
|
||||||
|
res,
|
||||||
|
});
|
||||||
if (!respData) return null;
|
if (!respData) return null;
|
||||||
|
|
||||||
let tmpData = structuredClone(respData);
|
let tmpData = structuredClone(respData);
|
||||||
@@ -32,7 +38,7 @@ const fetchUserPlaylists: RequestHandler = async (req, res) => {
|
|||||||
// keep getting batches of 50 till exhausted
|
// keep getting batches of 50 till exhausted
|
||||||
while (nextURL) {
|
while (nextURL) {
|
||||||
const nextData = await getCurrentUsersPlaylistsNextPage({
|
const nextData = await getCurrentUsersPlaylistsNextPage({
|
||||||
req,
|
authHeaders,
|
||||||
res,
|
res,
|
||||||
nextURL,
|
nextURL,
|
||||||
});
|
});
|
||||||
@@ -51,4 +57,5 @@ const fetchUserPlaylists: RequestHandler = async (req, res) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { fetchUserPlaylists };
|
export { fetchUserPlaylists };
|
||||||
|
|||||||
5
index.ts
5
index.ts
@@ -91,7 +91,10 @@ app.use("/health", (_req, res) => {
|
|||||||
});
|
});
|
||||||
app.use("/auth-health", isAuthenticated, async (req, res) => {
|
app.use("/auth-health", isAuthenticated, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const respData = await getCurrentUsersProfile({ req, res });
|
const { authHeaders } = req.session;
|
||||||
|
if (!authHeaders)
|
||||||
|
throw new ReferenceError("session does not have auth headers");
|
||||||
|
const respData = await getCurrentUsersProfile({ authHeaders, res });
|
||||||
if (!respData) return null;
|
if (!respData) return null;
|
||||||
res.status(200).send({ message: "OK" });
|
res.status(200).send({ message: "OK" });
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { AxiosRequestHeaders } from "axios";
|
|
||||||
import type { RequestHandler } from "express";
|
import type { RequestHandler } from "express";
|
||||||
|
|
||||||
import { sessionName } from "../constants.ts";
|
import { sessionName } from "../constants.ts";
|
||||||
@@ -9,7 +8,7 @@ export const isAuthenticated: RequestHandler = (req, res, next) => {
|
|||||||
if (req.session.accessToken) {
|
if (req.session.accessToken) {
|
||||||
req.session.authHeaders = {
|
req.session.authHeaders = {
|
||||||
Authorization: `Bearer ${req.session.accessToken}`,
|
Authorization: `Bearer ${req.session.accessToken}`,
|
||||||
} as AxiosRequestHeaders;
|
};
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
const delSession = req.session.destroy((error) => {
|
const delSession = req.session.destroy((error) => {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
const router: Router = Router();
|
const playlistRouter: Router = Router();
|
||||||
|
|
||||||
import { fetchUserPlaylists } from "../controllers/playlists.ts";
|
import { fetchUserPlaylists } from "../controllers/playlists.ts";
|
||||||
|
|
||||||
// import { validate } from "../validators/index.ts";
|
// import { validate } from "../validators/index.ts";
|
||||||
|
|
||||||
router.get("/me", fetchUserPlaylists);
|
playlistRouter.get("/me", fetchUserPlaylists);
|
||||||
|
|
||||||
export default router;
|
export default playlistRouter;
|
||||||
|
|||||||
4
types/express-session.d.ts
vendored
4
types/express-session.d.ts
vendored
@@ -1,4 +1,4 @@
|
|||||||
import type { AxiosRequestHeaders } from "axios";
|
import type { RawAxiosRequestHeaders } from "axios";
|
||||||
import type { User } from "spotify_manager/index.d.ts";
|
import type { User } from "spotify_manager/index.d.ts";
|
||||||
|
|
||||||
declare module "express-session" {
|
declare module "express-session" {
|
||||||
@@ -6,7 +6,7 @@ declare module "express-session" {
|
|||||||
interface SessionData {
|
interface SessionData {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
refreshToken: string;
|
refreshToken: string;
|
||||||
authHeaders: AxiosRequestHeaders;
|
authHeaders: RawAxiosRequestHeaders;
|
||||||
user: User;
|
user: User;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { RawAxiosRequestHeaders } from "axios";
|
||||||
import type { Request, Response, NextFunction } from "express";
|
import type { Request, Response, NextFunction } from "express";
|
||||||
|
|
||||||
export type Req = Request;
|
export type Req = Request;
|
||||||
@@ -5,6 +6,6 @@ export type Res = Response;
|
|||||||
export type Next = NextFunction;
|
export type Next = NextFunction;
|
||||||
|
|
||||||
export interface EndpointHandlerBaseArgs {
|
export interface EndpointHandlerBaseArgs {
|
||||||
req: Req;
|
authHeaders: RawAxiosRequestHeaders;
|
||||||
res: Res;
|
res: Res;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user