user-environments.service.ts 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. import { Injectable } from '@nestjs/common';
  2. import { UserEnvironment } from './user-environments.model';
  3. import { PrismaService } from '../prisma/prisma.service';
  4. import { PubSubService } from '../pubsub/pubsub.service';
  5. import * as E from 'fp-ts/Either';
  6. import * as O from 'fp-ts/Option';
  7. import {
  8. USER_ENVIRONMENT_ENV_DOES_NOT_EXISTS,
  9. USER_ENVIRONMENT_GLOBAL_ENV_DOES_NOT_EXISTS,
  10. USER_ENVIRONMENT_GLOBAL_ENV_DELETION_FAILED,
  11. USER_ENVIRONMENT_GLOBAL_ENV_EXISTS,
  12. USER_ENVIRONMENT_IS_NOT_GLOBAL,
  13. USER_ENVIRONMENT_UPDATE_FAILED,
  14. USER_ENVIRONMENT_INVALID_ENVIRONMENT_NAME,
  15. } from '../errors';
  16. import { stringToJson } from '../utils';
  17. @Injectable()
  18. export class UserEnvironmentsService {
  19. constructor(
  20. private readonly prisma: PrismaService,
  21. private readonly pubsub: PubSubService,
  22. ) {}
  23. /**
  24. * Fetch personal user environments
  25. * @param uid Users uid
  26. * @returns array of users personal environments
  27. */
  28. async fetchUserEnvironments(uid: string) {
  29. const environments = await this.prisma.userEnvironment.findMany({
  30. where: {
  31. userUid: uid,
  32. isGlobal: false,
  33. },
  34. });
  35. const userEnvironments: UserEnvironment[] = [];
  36. environments.forEach((environment) => {
  37. userEnvironments.push(<UserEnvironment>{
  38. userUid: environment.userUid,
  39. id: environment.id,
  40. name: environment.name,
  41. variables: JSON.stringify(environment.variables),
  42. isGlobal: environment.isGlobal,
  43. });
  44. });
  45. return userEnvironments;
  46. }
  47. /**
  48. * Fetch users global environment
  49. * @param uid Users uid
  50. * @returns an `UserEnvironment` object
  51. */
  52. async fetchUserGlobalEnvironment(uid: string) {
  53. const globalEnvironment = await this.prisma.userEnvironment.findFirst({
  54. where: {
  55. userUid: uid,
  56. isGlobal: true,
  57. },
  58. });
  59. if (globalEnvironment != null) {
  60. return E.right(<UserEnvironment>{
  61. userUid: globalEnvironment.userUid,
  62. id: globalEnvironment.id,
  63. name: globalEnvironment.name,
  64. variables: JSON.stringify(globalEnvironment.variables),
  65. isGlobal: globalEnvironment.isGlobal,
  66. });
  67. }
  68. return E.left(USER_ENVIRONMENT_ENV_DOES_NOT_EXISTS);
  69. }
  70. /**
  71. * Create a personal or global user environment
  72. * @param uid Users uid
  73. * @param name environments name, null if the environment is global
  74. * @param variables environment variables
  75. * @param isGlobal flag to indicate type of environment to create
  76. * @returns an `UserEnvironment` object
  77. */
  78. async createUserEnvironment(
  79. uid: string,
  80. name: string,
  81. variables: string,
  82. isGlobal: boolean,
  83. ) {
  84. // Check for existing global env for a user if exists error out to avoid recreation
  85. if (isGlobal) {
  86. const globalEnvExists = await this.checkForExistingGlobalEnv(uid);
  87. if (!O.isNone(globalEnvExists))
  88. return E.left(USER_ENVIRONMENT_GLOBAL_ENV_EXISTS);
  89. }
  90. if (name === null && !isGlobal)
  91. return E.left(USER_ENVIRONMENT_INVALID_ENVIRONMENT_NAME);
  92. const envVariables = stringToJson(variables);
  93. if (E.isLeft(envVariables)) return E.left(envVariables.left);
  94. const createdEnvironment = await this.prisma.userEnvironment.create({
  95. data: {
  96. userUid: uid,
  97. name: name,
  98. variables: envVariables.right,
  99. isGlobal: isGlobal,
  100. },
  101. });
  102. const userEnvironment: UserEnvironment = {
  103. userUid: createdEnvironment.userUid,
  104. id: createdEnvironment.id,
  105. name: createdEnvironment.name,
  106. variables: JSON.stringify(createdEnvironment.variables),
  107. isGlobal: createdEnvironment.isGlobal,
  108. };
  109. // Publish subscription for environment creation
  110. await this.pubsub.publish(
  111. `user_environment/${userEnvironment.userUid}/created`,
  112. userEnvironment,
  113. );
  114. return E.right(userEnvironment);
  115. }
  116. /**
  117. * Update an existing personal or global user environment
  118. * @param id environment id
  119. * @param name environments name
  120. * @param variables environment variables
  121. * @returns an Either of `UserEnvironment` or error
  122. */
  123. async updateUserEnvironment(id: string, name: string, variables: string) {
  124. const envVariables = stringToJson(variables);
  125. if (E.isLeft(envVariables)) return E.left(envVariables.left);
  126. try {
  127. const updatedEnvironment = await this.prisma.userEnvironment.update({
  128. where: { id: id },
  129. data: {
  130. name: name,
  131. variables: envVariables.right,
  132. },
  133. });
  134. const updatedUserEnvironment: UserEnvironment = {
  135. userUid: updatedEnvironment.userUid,
  136. id: updatedEnvironment.id,
  137. name: updatedEnvironment.name,
  138. variables: JSON.stringify(updatedEnvironment.variables),
  139. isGlobal: updatedEnvironment.isGlobal,
  140. };
  141. // Publish subscription for environment update
  142. await this.pubsub.publish(
  143. `user_environment/${updatedUserEnvironment.userUid}/updated`,
  144. updatedUserEnvironment,
  145. );
  146. return E.right(updatedUserEnvironment);
  147. } catch (e) {
  148. return E.left(USER_ENVIRONMENT_ENV_DOES_NOT_EXISTS);
  149. }
  150. }
  151. /**
  152. * Delete an existing personal user environment based on environment id
  153. * @param uid users uid
  154. * @param id environment id
  155. * @returns an Either of deleted `UserEnvironment` or error
  156. */
  157. async deleteUserEnvironment(uid: string, id: string) {
  158. try {
  159. // check if id is of a global environment if it is, don't delete and error out
  160. const globalEnvExists = await this.checkForExistingGlobalEnv(uid);
  161. if (O.isSome(globalEnvExists)) {
  162. const globalEnv = globalEnvExists.value;
  163. if (globalEnv.id === id) {
  164. return E.left(USER_ENVIRONMENT_GLOBAL_ENV_DELETION_FAILED);
  165. }
  166. }
  167. const deletedEnvironment = await this.prisma.userEnvironment.delete({
  168. where: {
  169. id: id,
  170. },
  171. });
  172. const deletedUserEnvironment: UserEnvironment = {
  173. userUid: deletedEnvironment.userUid,
  174. id: deletedEnvironment.id,
  175. name: deletedEnvironment.name,
  176. variables: JSON.stringify(deletedEnvironment.variables),
  177. isGlobal: deletedEnvironment.isGlobal,
  178. };
  179. // Publish subscription for environment deletion
  180. await this.pubsub.publish(
  181. `user_environment/${deletedUserEnvironment.userUid}/deleted`,
  182. deletedUserEnvironment,
  183. );
  184. return E.right(true);
  185. } catch (e) {
  186. return E.left(USER_ENVIRONMENT_ENV_DOES_NOT_EXISTS);
  187. }
  188. }
  189. /**
  190. * Deletes all existing personal user environments
  191. * @param uid user uid
  192. * @returns a count of environments deleted
  193. */
  194. async deleteUserEnvironments(uid: string) {
  195. const deletedEnvironments = await this.prisma.userEnvironment.deleteMany({
  196. where: {
  197. userUid: uid,
  198. isGlobal: false,
  199. },
  200. });
  201. // Publish subscription for multiple environment deletions
  202. await this.pubsub.publish(
  203. `user_environment/${uid}/deleted_many`,
  204. deletedEnvironments.count,
  205. );
  206. return deletedEnvironments.count;
  207. }
  208. /**
  209. * Removes all existing variables in a users global environment
  210. * @param uid users uid
  211. * @param id environment id
  212. * @returns an `` of environments deleted
  213. */
  214. async clearGlobalEnvironments(uid: string, id: string) {
  215. const globalEnvExists = await this.checkForExistingGlobalEnv(uid);
  216. if (O.isNone(globalEnvExists))
  217. return E.left(USER_ENVIRONMENT_GLOBAL_ENV_DOES_NOT_EXISTS);
  218. const env = globalEnvExists.value;
  219. if (env.id === id) {
  220. try {
  221. const updatedEnvironment = await this.prisma.userEnvironment.update({
  222. where: { id: id },
  223. data: {
  224. variables: [],
  225. },
  226. });
  227. const updatedUserEnvironment: UserEnvironment = {
  228. userUid: updatedEnvironment.userUid,
  229. id: updatedEnvironment.id,
  230. name: updatedEnvironment.name,
  231. variables: JSON.stringify(updatedEnvironment.variables),
  232. isGlobal: updatedEnvironment.isGlobal,
  233. };
  234. // Publish subscription for environment update
  235. await this.pubsub.publish(
  236. `user_environment/${updatedUserEnvironment.userUid}/updated`,
  237. updatedUserEnvironment,
  238. );
  239. return E.right(updatedUserEnvironment);
  240. } catch (e) {
  241. return E.left(USER_ENVIRONMENT_UPDATE_FAILED);
  242. }
  243. } else return E.left(USER_ENVIRONMENT_IS_NOT_GLOBAL);
  244. }
  245. // Method to check for existing global environments for a given user uid
  246. private async checkForExistingGlobalEnv(uid: string) {
  247. const globalEnv = await this.prisma.userEnvironment.findFirst({
  248. where: {
  249. userUid: uid,
  250. isGlobal: true,
  251. },
  252. });
  253. if (globalEnv == null) return O.none;
  254. return O.some(globalEnv);
  255. }
  256. }