api.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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. },
  102. };
  103. export const getGames = async () => {
  104. const fetchParams = new URLSearchParams({
  105. fields: "_id,board,owner",
  106. limit: 2000,
  107. });
  108. let gameList = [];
  109. const result = await fetch(`${gameURI}?${"" + fetchParams}`, {
  110. credentials: "include",
  111. });
  112. if (result.status === 200) {
  113. const serverGames = await result.json();
  114. gameList = serverGames.map((game) => ({
  115. id: game._id,
  116. owner: game.owner,
  117. board: game.board,
  118. url: `${gameURI}/${game._id}`,
  119. }));
  120. }
  121. if (!IS_PRODUCTION || import.meta.env.VITE_CI) {
  122. gameList = [testGame, perfGame, unpublishedGame, ...gameList];
  123. }
  124. gameList = [demoGame, ...gameList];
  125. return gameList;
  126. };
  127. const fetchGame = async (url) => {
  128. const result = await fetch(url, {
  129. credentials: "include",
  130. });
  131. return await result.json();
  132. };
  133. export const getGame = async (gameId) => {
  134. let game;
  135. switch (gameId) {
  136. // Demo games
  137. case "test":
  138. game = testGame;
  139. break;
  140. case "perf":
  141. game = perfGame;
  142. break;
  143. case "unpublished":
  144. game = unpublishedGame;
  145. break;
  146. // Real games
  147. default:
  148. game = await fetchGame(`${gameURI}/${gameId}`);
  149. }
  150. // Add id if missing
  151. game.items = game.items.map((item) => ({
  152. id: uid(),
  153. ...item,
  154. }));
  155. game.availableItems = game.availableItems.map((item) => ({
  156. id: uid(),
  157. ...item,
  158. }));
  159. return game;
  160. };
  161. export const createGame = async (data) => {
  162. const newGameId = uid();
  163. const result = await updateGame(newGameId, data);
  164. return result;
  165. };
  166. export const updateGame = async (gameId, data) => {
  167. // fake games
  168. if (["test", "perf", "unpublished", "demo"].includes(gameId)) {
  169. return data;
  170. }
  171. const result = await fetch(`${gameURI}/${gameId}`, {
  172. method: "POST",
  173. headers: {
  174. Accept: "application/json",
  175. "Content-Type": "application/json",
  176. },
  177. body: JSON.stringify(data),
  178. credentials: "include",
  179. });
  180. if (result.status === 404) {
  181. throw new Error("Resource not found");
  182. }
  183. if (result.status === 403) {
  184. throw new Error("Forbidden");
  185. }
  186. if (result.status >= 300) {
  187. throw new Error("Server error");
  188. }
  189. return await result.json();
  190. };
  191. export const deleteGame = async (gameId) => {
  192. const result = await fetch(`${gameURI}/${gameId}`, {
  193. method: "DELETE",
  194. credentials: "include",
  195. });
  196. if (result.status === 404) {
  197. throw new Error("Resource not found");
  198. }
  199. if (result.status === 403) {
  200. throw new Error("Forbidden");
  201. }
  202. if (result.status >= 300) {
  203. throw new Error("Server error");
  204. }
  205. return await result.json();
  206. };
  207. export const getSession = async (id) => {
  208. const result = await fetch(`${sessionURI}/${id}`, {
  209. method: "GET",
  210. headers: {
  211. Accept: "application/json",
  212. "Content-Type": "application/json",
  213. },
  214. credentials: "include",
  215. });
  216. if (result.status === 404) {
  217. throw new Error("Resource not found");
  218. }
  219. if (result.status === 403) {
  220. throw new Error("Forbidden");
  221. }
  222. if (result.status >= 300) {
  223. throw new Error("Server error");
  224. }
  225. return await result.json();
  226. };
  227. export const updateSession = async (id, data) => {
  228. const result = await fetch(`${sessionURI}/${id}`, {
  229. method: "POST",
  230. headers: {
  231. Accept: "application/json",
  232. "Content-Type": "application/json",
  233. },
  234. body: JSON.stringify(data),
  235. credentials: "include",
  236. });
  237. if (result.status === 404) {
  238. throw new Error("Resource not found");
  239. }
  240. if (result.status === 403) {
  241. throw new Error("Forbidden");
  242. }
  243. if (result.status >= 300) {
  244. throw new Error("Server error");
  245. }
  246. return await result.json();
  247. };
  248. export const getRoom = async (id) => {
  249. const result = await fetch(`${roomURI}/${id}`, {
  250. method: "GET",
  251. headers: {
  252. Accept: "application/json",
  253. "Content-Type": "application/json",
  254. },
  255. credentials: "include",
  256. });
  257. if (result.status === 404) {
  258. throw new Error("Resource not found");
  259. }
  260. if (result.status === 403) {
  261. throw new Error("Forbidden");
  262. }
  263. if (result.status >= 300) {
  264. throw new Error("Server error");
  265. }
  266. return await result.json();
  267. };
  268. export const updateRoom = async (id, data) => {
  269. const result = await fetch(`${roomURI}/${id}`, {
  270. method: "POST",
  271. headers: {
  272. Accept: "application/json",
  273. "Content-Type": "application/json",
  274. },
  275. body: JSON.stringify(data),
  276. credentials: "include",
  277. });
  278. if (result.status === 404) {
  279. throw new Error("Resource not found");
  280. }
  281. if (result.status === 403) {
  282. throw new Error("Forbidden");
  283. }
  284. if (result.status >= 300) {
  285. throw new Error("Server error");
  286. }
  287. return await result.json();
  288. };
  289. export const sendAuthToken = async (email) => {
  290. const result = await fetch(`${authURI}/`, {
  291. method: "POST",
  292. headers: {
  293. Accept: "application/json",
  294. "Content-Type": "application/json",
  295. },
  296. body: JSON.stringify({ userEmail: email }),
  297. credentials: "include",
  298. });
  299. if (result.status !== 200) {
  300. throw new Error("Can't send token");
  301. }
  302. };
  303. export const login = async (userHash, token) => {
  304. const result = await fetch(`${authURI}/verify/${userHash}/${token}`, {
  305. credentials: "include",
  306. });
  307. if (result.status !== 200) {
  308. throw new Error("Auth failed");
  309. }
  310. };
  311. export const checkAuthentication = async () => {
  312. const result = await fetch(`${authURI}/check`, {
  313. credentials: "include",
  314. });
  315. if (result.status !== 200) {
  316. return false;
  317. }
  318. return true;
  319. };
  320. export const logout = async () => {
  321. const result = await fetch(`${authURI}/logout/`, {
  322. credentials: "include",
  323. });
  324. if (result.status !== 200) {
  325. throw new Error("Logout failed");
  326. }
  327. };
  328. export const getConfToken = async (session) => {
  329. const result = await fetch(`${execURI}/getConfToken?session=${session}`, {
  330. credentials: "include",
  331. headers: {
  332. Accept: "application/json",
  333. "Content-Type": "application/json",
  334. },
  335. });
  336. if (result.status === 404) {
  337. throw new Error("Webconference not enabled");
  338. }
  339. if (result.status === 403) {
  340. throw new Error("Forbidden");
  341. }
  342. if (result.status >= 300) {
  343. throw new Error("Server error");
  344. }
  345. return await result.json();
  346. };
  347. export const getAccount = async (id) => {
  348. const result = await fetch(`${userURI}/${id}`, {
  349. method: "GET",
  350. headers: {
  351. Accept: "application/json",
  352. "Content-Type": "application/json",
  353. },
  354. credentials: "include",
  355. });
  356. if (result.status === 404) {
  357. throw new Error("Resource not found");
  358. }
  359. if (result.status === 403) {
  360. throw new Error("Forbidden");
  361. }
  362. if (result.status >= 300) {
  363. throw new Error("Server error");
  364. }
  365. return await result.json();
  366. };