182 lines
5.9 KiB
TypeScript
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;
|