2024-07-27 23:02:17 +02:00

182 lines
5.9 KiB
TypeScript

import { POST_LIMIT, PROFILE_POST_LIMIT } from '../constanst';
import { PostAuth, PostDelete, PostListAuth, PostListNonAuth, PostNew, PostUpdate } from '../types/Post';
import { User, UserImageUpdate, UserUpdate } from '../types/User';
const BASE = 'https://khofmann.userpage.fu-berlin.de/phpCourse/exam/api/';
let instance: ApiImpl;
class ApiImpl {
private token?: string;
private refreshToken?: string;
private self?: User;
private userListeners: ((user?: User) => void)[] = [];
constructor() {
if (instance) {
throw new Error('New instance cannot be created!!');
}
//eslint-disable-next-line @typescript-eslint/no-this-alias
instance = this;
}
public hasAuth = () => this.token !== undefined;
//FIXME: TESTING
public isAdmin = () => this.hasAuth() && this.self?.isAdmin;
public getAuthenticatedUser = () => this.self;
public getCurrentSession = () => [this.token, this.refreshToken];
public subscribeToAuthenticatedUser = (callback: (user?: User) => void) => {
this.userListeners.push(callback);
return () => {
this.userListeners = this.userListeners.filter((item) => item !== callback);
};
};
public logIn = async (email: string, password: string): Promise<void> => {
const { user, token } = await (await this.post('login', { email, password })).json();
this.self = user;
this.token = token;
this.userListeners.forEach((listener) => listener(user));
};
public logOut = async (): Promise<boolean> => {
try {
return await (await this.postAuth('logout')).json();
} catch {
return false;
} finally {
this.self = undefined;
this.token = undefined;
this.userListeners.forEach((listener) => listener());
}
};
public posts = async (page?: number): Promise<PostListNonAuth | PostListAuth> => {
const url = `posts?p=${page ?? 0}&l=${POST_LIMIT}`;
if (this.token) return await (await this.getAuth(url)).json();
return await (await this.get(url)).json();
};
public deletePost = async (id: number): Promise<PostDelete> => {
return await (await this.delete(`posts/${id}?l=${POST_LIMIT}`)).json();
};
public user = async (id?: number): Promise<User> => {
return await (await this.getAuth(`users/${id ?? this.self?.id}`)).json();
};
public updateUser = async (data: UserUpdate, id?: number): Promise<User> => {
const user = await (await this.patch(`users/${id ?? 'self'}`, data as Record<string, unknown>)).json();
this.self = user;
this.userListeners.forEach((listener) => listener(user));
return user;
};
public updateUserImage = async (data: UserImageUpdate, id?: number): Promise<User> => {
const formData = new FormData();
if (data.image) formData.append('image', data.image);
if (!data.image && data.predefined) formData.append('predefined', data.predefined);
const user = await (await this.postAuthRaw(`users/${id ?? 'self'}/image`, formData)).json();
this.self = user;
this.userListeners.forEach((listener) => listener(user));
return user;
};
public newPost = async (data: PostUpdate): Promise<PostNew> => {
return await (await this.postAuth(`posts?l=${POST_LIMIT}`, { ...data } as Record<string, unknown>)).json();
};
public updatePost = async (data: PostUpdate, id: number): Promise<PostAuth> => {
return await (await this.patch(`posts/${id}`, data as Record<string, unknown>)).json();
};
public userPosts = async (id?: number): Promise<PostListAuth> => {
return await (await this.getAuth(`users/${id}/posts?l=${PROFILE_POST_LIMIT}&s=desc`)).json();
};
/* Internal */
private post = async (endpoint: string, body?: Record<string, unknown>, headers?: HeadersInit) => {
const response = await fetch(`${BASE}${endpoint}`, {
mode: 'cors',
method: 'post',
headers,
body: JSON.stringify(body),
});
if (response.ok) return response;
throw await response.json();
};
private postAuth = async (endpoint: string, body?: Record<string, unknown>, headers?: HeadersInit) => {
const response = await fetch(`${BASE}${endpoint}`, {
mode: 'cors',
method: 'post',
headers: { token: this.token ?? '', ...headers },
body: JSON.stringify(body),
});
if (response.ok) return response;
throw await response.json();
};
private postAuthRaw = async (endpoint: string, body?: FormData, headers?: HeadersInit) => {
const response = await fetch(`${BASE}${endpoint}`, {
mode: 'cors',
method: 'post',
headers: { token: this.token ?? '', ...headers },
body,
});
if (response.ok) return response;
throw await response.json();
};
private get = async (endpoint: string, headers?: HeadersInit) => {
const response = await fetch(`${BASE}${endpoint}`, {
mode: 'cors',
method: 'get',
headers,
});
if (response.ok) return response;
throw await response.json();
};
private getAuth = async (endpoint: string, headers?: HeadersInit) => {
const response = await fetch(`${BASE}${endpoint}`, {
mode: 'cors',
method: 'get',
headers: { token: this.token ?? '', ...headers },
});
if (response.ok) return response;
throw await response.json();
};
private delete = async (endpoint: string, headers?: HeadersInit) => {
const response = await fetch(`${BASE}${endpoint}`, {
mode: 'cors',
method: 'delete',
headers: { token: this.token ?? '', ...headers },
});
if (response.ok) return response;
throw await response.json();
};
private patch = async (endpoint: string, body?: Record<string, unknown>, headers?: HeadersInit) => {
const response = await fetch(`${BASE}${endpoint}`, {
mode: 'cors',
method: 'patch',
headers: { token: this.token ?? '', ...headers },
body: JSON.stringify(body),
});
if (response.ok) return response;
throw await response.json();
};
}
const Api = new ApiImpl();
export default Api;