api.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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 { uid } from "./";
  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 userURI = `${API_ENDPOINT}/store/user`;
  11. const execURI = `${API_ENDPOINT}/execute`;
  12. const authURI = `${API_ENDPOINT}/auth`;
  13. export const uploadImage = async (namespace, file) => {
  14. const payload = new FormData();
  15. payload.append("file", file);
  16. const result = await fetch(`${oldUploadURI}/${namespace}/`, {
  17. method: "POST",
  18. body: payload, // this sets the `Content-Type` header to `multipart/form-data`
  19. });
  20. return await result.text();
  21. };
  22. export const uploadResourceImage = async (boxId, resourceId, file) => {
  23. const uploadGameURI = `${API_ENDPOINT}/store/${boxId}/${resourceId}/file`;
  24. const payload = new FormData();
  25. payload.append("file", file);
  26. const result = await fetch(`${uploadGameURI}/`, {
  27. method: "POST",
  28. body: payload, // this sets the `Content-Type` header to `multipart/form-data`
  29. credentials: "include",
  30. });
  31. return await result.text();
  32. };
  33. export const listResourceImage = async (boxId, resourceId) => {
  34. const uploadGameURI = `${API_ENDPOINT}/store/${boxId}/${resourceId}/file`;
  35. const result = await fetch(`${uploadGameURI}/`, {
  36. method: "GET",
  37. credentials: "include",
  38. });
  39. return await result.json();
  40. };
  41. export const deleteResourceImage = async (filePath) => {
  42. const result = await fetch(`${API_BASE}/${filePath}`, {
  43. method: "DELETE",
  44. credentials: "include",
  45. });
  46. return await result.json();
  47. };
  48. export const getBestTranslationFromConfig = (
  49. {
  50. translations = [],
  51. defaultLanguage,
  52. defaultName,
  53. defaultDescription,
  54. name,
  55. info,
  56. } = {},
  57. langs
  58. ) => {
  59. const translationsMap = {
  60. [defaultLanguage || "en"]: {
  61. name: defaultName || name,
  62. description: defaultDescription || info,
  63. },
  64. };
  65. translations.forEach((translation) => {
  66. translationsMap[translation.language] = translation;
  67. });
  68. for (let lang in langs) {
  69. if (translationsMap[langs[lang]]) {
  70. return translationsMap[langs[lang]];
  71. }
  72. }
  73. return translationsMap[defaultLanguage || "en"];
  74. };
  75. const demoGame = {
  76. id: "demo",
  77. owner: "nobody",
  78. board: {
  79. published: true,
  80. defaultName: "How to play?",
  81. bgType: "default",
  82. playerCount: [],
  83. duration: [],
  84. gridSize: 1,
  85. defaultLanguage: "en",
  86. materialLanguage: "Multi-lang",
  87. defaultBaseline: "Learn how to play with Airboardgame",
  88. imageUrl: "/game_assets/default.png",
  89. keepTitle: true,
  90. defaultDescription:
  91. "# Demo game\n\nThis is a demo game to learn how to play with Airboardgame.\n\nFor other games, you can find useful information about the game like the creator name or the rules.",
  92. translations: [
  93. {
  94. language: "fr",
  95. name: "Comment jouer ?",
  96. baseline: "Apprenez à jouer avec Airboardgame",
  97. description:
  98. "# Démonstration\n\nCe jeu vous permet d'apprendre à jouer avec Airboardgame.\n\nPour les autres jeux, vous trouverez dans cette section différentes choses utiles comme le nom de l'auteur ou les règles.",
  99. },
  100. {
  101. language: "it",
  102. name: "Come giocare?",
  103. baseline: "Imparate a giocare con Airboardgame",
  104. description:
  105. "# Gioco demo\n\nQuesto è un gioco demo per imparare a giocare con Airboardgame.\n\nPer gli altri giochi, potrete trovare informazioni utili o i regolamenti.",
  106. },
  107. ],
  108. },
  109. };
  110. export const getGames = async () => {
  111. const fetchParams = new URLSearchParams({
  112. fields: "_id,board,owner",
  113. limit: 2000,
  114. });
  115. let gameList = [];
  116. const result = await fetch(`${gameURI}?${"" + fetchParams}`, {
  117. credentials: "include",
  118. });
  119. if (result.status === 200) {
  120. const serverGames = await result.json();
  121. gameList = serverGames.map((game) => ({
  122. id: game._id,
  123. owner: game.owner,
  124. board: game.board,
  125. url: `${gameURI}/${game._id}`,
  126. }));
  127. }
  128. if (!IS_PRODUCTION || import.meta.env.VITE_CI) {
  129. gameList = [testGame, perfGame, unpublishedGame, ...gameList];
  130. }
  131. gameList = [demoGame, ...gameList];
  132. return gameList;
  133. };
  134. const fetchGame = async (url) => {
  135. const result = await fetch(url, {
  136. credentials: "include",
  137. });
  138. return await result.json();
  139. };
  140. export const getGame = async (gameId) => {
  141. let game;
  142. switch (gameId) {
  143. // Demo games
  144. case "test":
  145. game = testGame;
  146. break;
  147. case "perf":
  148. game = perfGame;
  149. break;
  150. case "unpublished":
  151. game = unpublishedGame;
  152. break;
  153. // Real games
  154. default:
  155. game = await fetchGame(`${gameURI}/${gameId}`);
  156. }
  157. // Add id if missing
  158. game.items = game.items.map((item) => ({
  159. id: uid(),
  160. ...item,
  161. }));
  162. game.availableItems = game.availableItems.map((item) => ({
  163. id: uid(),
  164. ...item,
  165. }));
  166. return game;
  167. };
  168. export const createGame = async (data) => {
  169. const newGameId = uid();
  170. const result = await updateGame(newGameId, data);
  171. return result;
  172. };
  173. export const updateGame = async (gameId, data) => {
  174. // fake games
  175. if (["test", "perf", "unpublished", "demo"].includes(gameId)) {
  176. return data;
  177. }
  178. const result = await fetch(`${gameURI}/${gameId}`, {
  179. method: "POST",
  180. headers: {
  181. Accept: "application/json",
  182. "Content-Type": "application/json",
  183. },
  184. body: JSON.stringify(data),
  185. credentials: "include",
  186. });
  187. if (result.status === 404) {
  188. throw new Error("Resource not found");
  189. }
  190. if (result.status === 403) {
  191. throw new Error("Forbidden");
  192. }
  193. if (result.status >= 300) {
  194. throw new Error("Server error");
  195. }
  196. return await result.json();
  197. };
  198. export const deleteGame = async (gameId) => {
  199. const result = await fetch(`${gameURI}/${gameId}`, {
  200. method: "DELETE",
  201. credentials: "include",
  202. });
  203. if (result.status === 404) {
  204. throw new Error("Resource not found");
  205. }
  206. if (result.status === 403) {
  207. throw new Error("Forbidden");
  208. }
  209. if (result.status >= 300) {
  210. throw new Error("Server error");
  211. }
  212. return await result.json();
  213. };
  214. export const getSession = async (id) => {
  215. const result = await fetch(`${sessionURI}/${id}`, {
  216. method: "GET",
  217. headers: {
  218. Accept: "application/json",
  219. "Content-Type": "application/json",
  220. },
  221. credentials: "include",
  222. });
  223. if (result.status === 404) {
  224. throw new Error("Resource not found");
  225. }
  226. if (result.status === 403) {
  227. throw new Error("Forbidden");
  228. }
  229. if (result.status >= 300) {
  230. throw new Error("Server error");
  231. }
  232. return await result.json();
  233. };
  234. export const updateSession = async (id, data) => {
  235. const result = await fetch(`${sessionURI}/${id}`, {
  236. method: "POST",
  237. headers: {
  238. Accept: "application/json",
  239. "Content-Type": "application/json",
  240. },
  241. body: JSON.stringify(data),
  242. credentials: "include",
  243. });
  244. if (result.status === 404) {
  245. throw new Error("Resource not found");
  246. }
  247. if (result.status === 403) {
  248. throw new Error("Forbidden");
  249. }
  250. if (result.status >= 300) {
  251. throw new Error("Server error");
  252. }
  253. return await result.json();
  254. };
  255. export const getRoom = async (id) => {
  256. const result = await fetch(`${roomURI}/${id}`, {
  257. method: "GET",
  258. headers: {
  259. Accept: "application/json",
  260. "Content-Type": "application/json",
  261. },
  262. credentials: "include",
  263. });
  264. if (result.status === 404) {
  265. throw new Error("Resource not found");
  266. }
  267. if (result.status === 403) {
  268. throw new Error("Forbidden");
  269. }
  270. if (result.status >= 300) {
  271. throw new Error("Server error");
  272. }
  273. return await result.json();
  274. };
  275. export const updateRoom = async (id, data) => {
  276. const result = await fetch(`${roomURI}/${id}`, {
  277. method: "POST",
  278. headers: {
  279. Accept: "application/json",
  280. "Content-Type": "application/json",
  281. },
  282. body: JSON.stringify(data),
  283. credentials: "include",
  284. });
  285. if (result.status === 404) {
  286. throw new Error("Resource not found");
  287. }
  288. if (result.status === 403) {
  289. throw new Error("Forbidden");
  290. }
  291. if (result.status >= 300) {
  292. throw new Error("Server error");
  293. }
  294. return await result.json();
  295. };
  296. export const sendAuthToken = async (email) => {
  297. const result = await fetch(`${authURI}/`, {
  298. method: "POST",
  299. headers: {
  300. Accept: "application/json",
  301. "Content-Type": "application/json",
  302. },
  303. body: JSON.stringify({ userEmail: email }),
  304. credentials: "include",
  305. });
  306. if (result.status !== 200) {
  307. throw new Error("Can't send token");
  308. }
  309. };
  310. export const login = async (userHash, token) => {
  311. const result = await fetch(`${authURI}/verify/${userHash}/${token}`, {
  312. credentials: "include",
  313. });
  314. if (result.status !== 200) {
  315. throw new Error("Auth failed");
  316. }
  317. };
  318. export const checkAuthentication = async () => {
  319. const result = await fetch(`${authURI}/check`, {
  320. credentials: "include",
  321. });
  322. if (result.status !== 200) {
  323. return false;
  324. }
  325. return true;
  326. };
  327. export const logout = async () => {
  328. const result = await fetch(`${authURI}/logout/`, {
  329. credentials: "include",
  330. });
  331. if (result.status !== 200) {
  332. throw new Error("Logout failed");
  333. }
  334. };
  335. export const getConfToken = async (session) => {
  336. const result = await fetch(`${execURI}/getConfToken?session=${session}`, {
  337. credentials: "include",
  338. headers: {
  339. Accept: "application/json",
  340. "Content-Type": "application/json",
  341. },
  342. });
  343. if (result.status === 404) {
  344. throw new Error("Webconference not enabled");
  345. }
  346. if (result.status === 403) {
  347. throw new Error("Forbidden");
  348. }
  349. if (result.status >= 300) {
  350. throw new Error("Server error");
  351. }
  352. return await result.json();
  353. };
  354. export const getAccount = async (id) => {
  355. const result = await fetch(`${userURI}/${id}`, {
  356. method: "GET",
  357. headers: {
  358. Accept: "application/json",
  359. "Content-Type": "application/json",
  360. },
  361. credentials: "include",
  362. });
  363. if (result.status === 404) {
  364. throw new Error("Resource not found");
  365. }
  366. if (result.status === 403) {
  367. throw new Error("Forbidden");
  368. }
  369. if (result.status >= 300) {
  370. throw new Error("Server error");
  371. }
  372. return await result.json();
  373. };