api.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. import { API_ENDPOINT, IS_PRODUCTION, API_BASE } from "./settings";
  2. import testGame from "../games/testGame";
  3. import perfGame from "../games/perfGame";
  4. import unpublishedGame from "../games/unpublishedGame";
  5. import { nanoid } from "nanoid";
  6. const oldUploadURI = `${API_ENDPOINT}/file`;
  7. const gameURI = `${API_ENDPOINT}/store/game`;
  8. const sessionURI = `${API_ENDPOINT}/store/session`;
  9. const roomURI = `${API_ENDPOINT}/store/room`;
  10. const execURI = `${API_ENDPOINT}/execute`;
  11. const authURI = `${API_ENDPOINT}/auth`;
  12. export const uploadImage = async (namespace, file) => {
  13. const payload = new FormData();
  14. payload.append("file", file);
  15. const result = await fetch(`${oldUploadURI}/${namespace}/`, {
  16. method: "POST",
  17. body: payload, // this sets the `Content-Type` header to `multipart/form-data`
  18. });
  19. return await result.text();
  20. };
  21. export const uploadResourceImage = async (boxId, resourceId, file) => {
  22. const uploadGameURI = `${API_ENDPOINT}/store/${boxId}/${resourceId}/file`;
  23. const payload = new FormData();
  24. payload.append("file", file);
  25. const result = await fetch(`${uploadGameURI}/`, {
  26. method: "POST",
  27. body: payload, // this sets the `Content-Type` header to `multipart/form-data`
  28. credentials: "include",
  29. });
  30. return await result.text();
  31. };
  32. export const listResourceImage = async (boxId, resourceId) => {
  33. const uploadGameURI = `${API_ENDPOINT}/store/${boxId}/${resourceId}/file`;
  34. const result = await fetch(`${uploadGameURI}/`, {
  35. method: "GET",
  36. credentials: "include",
  37. });
  38. return await result.json();
  39. };
  40. export const deleteResourceImage = async (filePath) => {
  41. const result = await fetch(`${API_BASE}/${filePath}`, {
  42. method: "DELETE",
  43. credentials: "include",
  44. });
  45. return await result.json();
  46. };
  47. export const getBestTranslationFromConfig = (
  48. {
  49. translations = [],
  50. defaultLanguage,
  51. defaultName,
  52. defaultDescription,
  53. name,
  54. info,
  55. } = {},
  56. langs
  57. ) => {
  58. const translationsMap = {
  59. [defaultLanguage || "en"]: {
  60. name: defaultName || name,
  61. description: defaultDescription || info,
  62. },
  63. };
  64. translations.forEach((translation) => {
  65. translationsMap[translation.language] = translation;
  66. });
  67. for (let lang in langs) {
  68. if (translationsMap[langs[lang]]) {
  69. return translationsMap[langs[lang]];
  70. }
  71. }
  72. return translationsMap[defaultLanguage || "en"];
  73. };
  74. export const getGames = async () => {
  75. const fetchParams = new URLSearchParams({
  76. fields: "_id,board,owner",
  77. limit: 2000,
  78. });
  79. let gameList = [];
  80. const result = await fetch(`${gameURI}?${"" + fetchParams}`, {
  81. credentials: "include",
  82. });
  83. if (result.status === 200) {
  84. const serverGames = await result.json();
  85. gameList = serverGames.map((game) => ({
  86. name: game.board.defaultName || game.board.name,
  87. id: game._id,
  88. owner: game.owner,
  89. ...game.board,
  90. board: game.board,
  91. url: `${gameURI}/${game._id}`,
  92. }));
  93. }
  94. if (!IS_PRODUCTION || import.meta.env.VITE_CI) {
  95. gameList = [
  96. {
  97. ...testGame,
  98. name: "Test Game",
  99. data: testGame,
  100. id: "test",
  101. published: true,
  102. ...testGame.board,
  103. },
  104. {
  105. ...perfGame,
  106. name: "Perf Test",
  107. data: perfGame,
  108. id: "perf",
  109. published: true,
  110. ...perfGame.board,
  111. },
  112. {
  113. ...unpublishedGame,
  114. name: "Unpublished Game",
  115. data: unpublishedGame,
  116. id: "unpublished",
  117. published: false,
  118. ...unpublishedGame.board,
  119. },
  120. ...gameList,
  121. ];
  122. }
  123. return gameList;
  124. };
  125. const fetchGame = async (url) => {
  126. const result = await fetch(url, {
  127. credentials: "include",
  128. });
  129. return await result.json();
  130. };
  131. export const getGame = async (gameId) => {
  132. let game;
  133. switch (gameId) {
  134. // Demo games
  135. case "test":
  136. game = testGame;
  137. break;
  138. case "perf":
  139. game = perfGame;
  140. break;
  141. case "unpublished":
  142. game = unpublishedGame;
  143. break;
  144. // Real games
  145. default:
  146. game = await fetchGame(`${gameURI}/${gameId}`);
  147. }
  148. // Add id if missing
  149. game.items = game.items.map((item) => ({
  150. id: nanoid(),
  151. ...item,
  152. }));
  153. game.availableItems = game.availableItems.map((item) => ({
  154. id: nanoid(),
  155. ...item,
  156. }));
  157. return game;
  158. };
  159. export const createGame = async (data) => {
  160. const newGameId = nanoid();
  161. const result = await updateGame(newGameId, data);
  162. return result;
  163. };
  164. export const updateGame = async (gameId, data) => {
  165. // fake games
  166. if (["test", "perf", "unpublished"].includes(gameId)) {
  167. return data;
  168. }
  169. const result = await fetch(`${gameURI}/${gameId}`, {
  170. method: "POST",
  171. headers: {
  172. Accept: "application/json",
  173. "Content-Type": "application/json",
  174. },
  175. body: JSON.stringify(data),
  176. credentials: "include",
  177. });
  178. if (result.status === 404) {
  179. throw new Error("Resource not found");
  180. }
  181. if (result.status === 403) {
  182. throw new Error("Forbidden");
  183. }
  184. if (result.status >= 300) {
  185. throw new Error("Server error");
  186. }
  187. return await result.json();
  188. };
  189. export const deleteGame = async (gameId) => {
  190. const result = await fetch(`${gameURI}/${gameId}`, {
  191. method: "DELETE",
  192. credentials: "include",
  193. });
  194. if (result.status === 404) {
  195. throw new Error("Resource not found");
  196. }
  197. if (result.status === 403) {
  198. throw new Error("Forbidden");
  199. }
  200. if (result.status >= 300) {
  201. throw new Error("Server error");
  202. }
  203. return await result.json();
  204. };
  205. export const getSession = async (id) => {
  206. const result = await fetch(`${sessionURI}/${id}`, {
  207. method: "GET",
  208. headers: {
  209. Accept: "application/json",
  210. "Content-Type": "application/json",
  211. },
  212. credentials: "include",
  213. });
  214. if (result.status === 404) {
  215. throw new Error("Resource not found");
  216. }
  217. if (result.status === 403) {
  218. throw new Error("Forbidden");
  219. }
  220. if (result.status >= 300) {
  221. throw new Error("Server error");
  222. }
  223. return await result.json();
  224. };
  225. export const updateSession = async (id, data) => {
  226. const result = await fetch(`${sessionURI}/${id}`, {
  227. method: "POST",
  228. headers: {
  229. Accept: "application/json",
  230. "Content-Type": "application/json",
  231. },
  232. body: JSON.stringify(data),
  233. credentials: "include",
  234. });
  235. if (result.status === 404) {
  236. throw new Error("Resource not found");
  237. }
  238. if (result.status === 403) {
  239. throw new Error("Forbidden");
  240. }
  241. if (result.status >= 300) {
  242. throw new Error("Server error");
  243. }
  244. return await result.json();
  245. };
  246. export const getRoom = async (id) => {
  247. const result = await fetch(`${roomURI}/${id}`, {
  248. method: "GET",
  249. headers: {
  250. Accept: "application/json",
  251. "Content-Type": "application/json",
  252. },
  253. credentials: "include",
  254. });
  255. if (result.status === 404) {
  256. throw new Error("Resource not found");
  257. }
  258. if (result.status === 403) {
  259. throw new Error("Forbidden");
  260. }
  261. if (result.status >= 300) {
  262. throw new Error("Server error");
  263. }
  264. return await result.json();
  265. };
  266. export const updateRoom = async (id, data) => {
  267. const result = await fetch(`${roomURI}/${id}`, {
  268. method: "POST",
  269. headers: {
  270. Accept: "application/json",
  271. "Content-Type": "application/json",
  272. },
  273. body: JSON.stringify(data),
  274. credentials: "include",
  275. });
  276. if (result.status === 404) {
  277. throw new Error("Resource not found");
  278. }
  279. if (result.status === 403) {
  280. throw new Error("Forbidden");
  281. }
  282. if (result.status >= 300) {
  283. throw new Error("Server error");
  284. }
  285. return await result.json();
  286. };
  287. export const sendAuthToken = async (email) => {
  288. const result = await fetch(`${authURI}/`, {
  289. method: "POST",
  290. headers: {
  291. Accept: "application/json",
  292. "Content-Type": "application/json",
  293. },
  294. body: JSON.stringify({ userEmail: email }),
  295. credentials: "include",
  296. });
  297. if (result.status !== 200) {
  298. throw new Error("Can't send token");
  299. }
  300. };
  301. export const login = async (userHash, token) => {
  302. const result = await fetch(`${authURI}/verify/${userHash}/${token}`, {
  303. credentials: "include",
  304. });
  305. if (result.status !== 200) {
  306. throw new Error("Auth failed");
  307. }
  308. };
  309. export const checkAuthentication = async () => {
  310. const result = await fetch(`${authURI}/check`, {
  311. credentials: "include",
  312. });
  313. if (result.status !== 200) {
  314. return false;
  315. }
  316. return true;
  317. };
  318. export const logout = async () => {
  319. const result = await fetch(`${authURI}/logout/`, {
  320. credentials: "include",
  321. });
  322. if (result.status !== 200) {
  323. throw new Error("Logout failed");
  324. }
  325. };
  326. export const getConfToken = async (session) => {
  327. const result = await fetch(`${execURI}/getConfToken?session=${session}`, {
  328. credentials: "include",
  329. headers: {
  330. Accept: "application/json",
  331. "Content-Type": "application/json",
  332. },
  333. });
  334. if (result.status === 404) {
  335. throw new Error("Webconference not enabled");
  336. }
  337. if (result.status === 403) {
  338. throw new Error("Forbidden");
  339. }
  340. if (result.status >= 300) {
  341. throw new Error("Server error");
  342. }
  343. return await result.json();
  344. };