workspace.controller.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // api/workspaces/workspace.controller.js
  2. import * as fs from "fs";
  3. import * as path from "path";
  4. import _ from "lodash";
  5. import WorkspaceService from "./workspace.service.js";
  6. import WorkspaceSerializer from "./workspace.serializer.js";
  7. import WorkspaceValidator from "./workspace.validator.js";
  8. class Controller {
  9. async index(req, res) {
  10. const workspaces = await WorkspaceService.find({
  11. $or: [
  12. { userId: req.user._id },
  13. { "teams._id": { $in: req.user.teams?.map(team => team._id) || [] } },
  14. { "members.userId": req.user._id } // Add this to support the new members field
  15. ],
  16. accountId: req.user.accountId
  17. });
  18. return res.json(WorkspaceSerializer.index(workspaces));
  19. }
  20. async byId(req, res) {
  21. const workspace = await WorkspaceService.findByIdAndUser(
  22. req.params.id,
  23. req.user._id,
  24. req.user.accountId
  25. );
  26. if (workspace) {
  27. // Update last accessed timestamp
  28. await WorkspaceService.update(
  29. workspace._id,
  30. req.user._id,
  31. req.user.accountId,
  32. { lastAccessed: new Date() }
  33. );
  34. return res.json(WorkspaceSerializer.show(workspace));
  35. } else {
  36. return res.status(404).json({
  37. success: false,
  38. message: "Workspace not found."
  39. });
  40. }
  41. }
  42. async create(req, res) {
  43. const errors = await WorkspaceValidator.onCreate(req.body);
  44. if (errors) {
  45. return res.status(422).json({
  46. success: false,
  47. errors: errors.details,
  48. });
  49. }
  50. // Add the current user to the members array if not already included
  51. const members = req.body.members || [];
  52. const userAlreadyMember = members.some(member =>
  53. member.userId && member.userId.toString() === req.user._id.toString()
  54. );
  55. if (!userAlreadyMember) {
  56. members.push({
  57. userId: req.user._id,
  58. name: req.user.name,
  59. email: req.user.email,
  60. role: "admin",
  61. joinedAt: new Date()
  62. });
  63. }
  64. const workspaceData = _.pick(req.body, [
  65. "name",
  66. "slug",
  67. "description",
  68. "timezone",
  69. "filePath",
  70. "fileType",
  71. "fileSize",
  72. "metadata",
  73. "isPublic",
  74. "teams",
  75. "contacts",
  76. "projects",
  77. "meetings",
  78. "notes",
  79. "tasks",
  80. "mysqlHost",
  81. "mysqlPort",
  82. "mysqlUser",
  83. "mysqlPassword",
  84. "mysqlDatabase",
  85. "mysqlTable",
  86. "mysqlConnectionType"
  87. ]);
  88. // Add the members array
  89. workspaceData.members = members;
  90. // Set the ownerId to the current user
  91. workspaceData.ownerId = req.user._id;
  92. const workspace = await WorkspaceService.create(
  93. workspaceData,
  94. req.user._id,
  95. req.user.accountId
  96. );
  97. if (workspace) {
  98. return res.json(WorkspaceSerializer.show(workspace));
  99. } else {
  100. return res.status(422).json({
  101. success: false,
  102. message: "Failed to create workspace."
  103. });
  104. }
  105. }
  106. async update(req, res) {
  107. const errors = await WorkspaceValidator.onUpdate(req.body);
  108. if (errors) {
  109. return res.status(422).json({
  110. success: false,
  111. errors: errors.details,
  112. });
  113. }
  114. const workspaceData = _.pick(req.body, [
  115. "name",
  116. "slug",
  117. "description",
  118. "timezone",
  119. "filePath",
  120. "fileType",
  121. "fileSize",
  122. "metadata",
  123. "isPublic",
  124. "teams",
  125. "members",
  126. "contacts",
  127. "projects",
  128. "meetings",
  129. "notes",
  130. "tasks",
  131. "mysqlHost",
  132. "mysqlPort",
  133. "mysqlUser",
  134. "mysqlPassword",
  135. "mysqlDatabase",
  136. "mysqlTable",
  137. "mysqlConnectionType"
  138. ]);
  139. const workspace = await WorkspaceService.update(
  140. req.params.id,
  141. req.user._id,
  142. req.user.accountId,
  143. workspaceData
  144. );
  145. if (workspace) {
  146. return res.json(WorkspaceSerializer.show(workspace));
  147. } else {
  148. return res.status(422).json({
  149. success: false,
  150. message: "Failed to update workspace or workspace not found."
  151. });
  152. }
  153. }
  154. async delete(req, res) {
  155. const result = await WorkspaceService.delete(
  156. req.params.id,
  157. req.user._id,
  158. req.user.accountId
  159. );
  160. if (result) {
  161. return res.json({
  162. success: true,
  163. message: "Workspace deleted successfully."
  164. });
  165. } else {
  166. return res.status(404).json({
  167. success: false,
  168. message: "Workspace not found or you don't have permission to delete it."
  169. });
  170. }
  171. }
  172. async getWorkspaceFile(req, res) {
  173. // Existing implementation, unchanged
  174. try {
  175. const workspaceName = req.params.name;
  176. // Validate workspace name to prevent directory traversal
  177. if (!WorkspaceService.isValidWorkspaceFileName(workspaceName)) {
  178. return res.status(400).json({
  179. success: false,
  180. message: "Invalid workspace file name."
  181. });
  182. }
  183. const filePath = await WorkspaceService.getWorkspaceFilePath(workspaceName);
  184. // Check if the file exists
  185. const fileExists = await WorkspaceService.workspaceFileExists(filePath);
  186. if (!fileExists) {
  187. return res.status(404).json({
  188. success: false,
  189. message: "Workspace file not found."
  190. });
  191. }
  192. // Determine content type
  193. const contentType = WorkspaceService.getContentType(workspaceName);
  194. if (contentType) {
  195. res.set('Content-Type', contentType);
  196. }
  197. // Set filename for download
  198. res.set('Content-Disposition', `attachment; filename="${workspaceName}"`);
  199. // Send the file
  200. res.sendFile(filePath, (err) => {
  201. if (err) {
  202. console.error('Error sending file:', err);
  203. res.status(500).json({
  204. success: false,
  205. message: "Error sending workspace file."
  206. });
  207. }
  208. });
  209. } catch (error) {
  210. console.error('Error retrieving workspace file:', error);
  211. res.status(500).json({
  212. success: false,
  213. message: "Failed to retrieve workspace file."
  214. });
  215. }
  216. }
  217. // The database methods remain unchanged
  218. async getTableData(req, res) {
  219. try {
  220. const workspaceId = req.params.id;
  221. const limit = req.query.limit ? parseInt(req.query.limit) : 100;
  222. // Get the table data from the service
  223. const result = await WorkspaceService.getTableData(
  224. workspaceId,
  225. req.user._id,
  226. req.user.accountId,
  227. limit
  228. );
  229. return res.json({
  230. success: true,
  231. data: result
  232. });
  233. } catch (error) {
  234. console.error('Error fetching table data:', error);
  235. return res.status(500).json({
  236. success: false,
  237. message: error.message || "Failed to retrieve table data."
  238. });
  239. }
  240. }
  241. async listTables(req, res) {
  242. try {
  243. const workspaceId = req.params.id;
  244. // Get list of tables from the service
  245. const tables = await WorkspaceService.listTables(
  246. workspaceId,
  247. req.user._id,
  248. req.user.accountId
  249. );
  250. return res.json({
  251. success: true,
  252. tables: tables
  253. });
  254. } catch (error) {
  255. console.error('Error listing tables:', error);
  256. return res.status(500).json({
  257. success: false,
  258. message: error.message || "Failed to list database tables."
  259. });
  260. }
  261. }
  262. async testConnection(req, res) {
  263. try {
  264. const workspaceId = req.params.id;
  265. // Test the database connection
  266. const result = await WorkspaceService.testDatabaseConnection(
  267. workspaceId,
  268. req.user._id,
  269. req.user.accountId
  270. );
  271. return res.json({
  272. success: true,
  273. message: "Database connection successful",
  274. details: result
  275. });
  276. } catch (error) {
  277. console.error('Error testing database connection:', error);
  278. return res.status(500).json({
  279. success: false,
  280. message: error.message || "Failed to connect to database."
  281. });
  282. }
  283. }
  284. }
  285. export default new Controller();