musare.sh 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. #!/bin/bash
  2. export PATH=/usr/local/bin:/usr/bin:/bin
  3. CYAN='\033[33;36m';
  4. RED='\033[0;31m'
  5. YELLOW='\033[0;93m'
  6. GREEN='\033[0;32m'
  7. NC='\033[0m'
  8. scriptLocation=$(dirname -- "$(readlink -fn -- "$0"; echo x)")
  9. cd "${scriptLocation%x}" || exit 1
  10. if [[ -f .env ]]; then
  11. # shellcheck disable=SC1091
  12. source .env
  13. else
  14. echo -e "${RED}Error: .env does not exist${NC}"
  15. exit 2
  16. fi
  17. if [[ -z ${DOCKER_COMMAND} ]]; then
  18. DOCKER_COMMAND="docker"
  19. elif [[ ${DOCKER_COMMAND} != "docker" && ${DOCKER_COMMAND} != "podman" ]]; then
  20. echo -e "${RED}Error: Invalid DOCKER_COMMAND${NC}"
  21. exit 1
  22. fi
  23. docker="${DOCKER_COMMAND}"
  24. dockerCompose="${DOCKER_COMMAND}-compose"
  25. if [[ ! -x "$(command -v ${docker})" || ! -x "$(command -v ${dockerCompose})" ]]; then
  26. if [[ -x "$(command -v ${docker})" && ! -x "$(command -v ${dockerCompose})" ]]; then
  27. echo -e "${RED}Error: ${dockerCompose} not installed.${NC}"
  28. elif [[ ! -x "$(command -v ${docker})" && -x "$(command -v ${dockerCompose})" ]]; then
  29. echo -e "${RED}Error: ${docker} not installed.${NC}"
  30. else
  31. echo -e "${RED}Error: ${docker} and ${dockerCompose} not installed.${NC}"
  32. fi
  33. exit 1
  34. fi
  35. composeFiles="-f docker-compose.yml"
  36. if [[ ${CONTAINER_MODE} == "dev" ]]; then
  37. composeFiles="${composeFiles} -f docker-compose.dev.yml"
  38. fi
  39. if [[ -f docker-compose.override.yml ]]; then
  40. composeFiles="${composeFiles} -f docker-compose.override.yml"
  41. fi
  42. dockerCompose="${dockerCompose} ${composeFiles}"
  43. handleServices()
  44. {
  45. validServices=($1)
  46. servicesArray=()
  47. invalidServices=false
  48. for x in "${@:2}"; do
  49. if [[ ${validServices[*]} =~ (^|[[:space:]])"$x"($|[[:space:]]) ]]; then
  50. if ! [[ ${servicesArray[*]} =~ (^|[[:space:]])"$x"($|[[:space:]]) ]]; then
  51. servicesArray+=("${x}")
  52. fi
  53. else
  54. if [[ $invalidServices == false ]]; then
  55. invalidServices="${x}"
  56. else
  57. invalidServices="${invalidServices} ${x}"
  58. fi
  59. fi
  60. done
  61. if [[ $invalidServices == false && ${#servicesArray[@]} -gt 0 ]]; then
  62. echo "1|${servicesArray[*]}"
  63. elif [[ $invalidServices == false ]]; then
  64. echo "1|all"
  65. else
  66. echo "0|Invalid Service(s): ${invalidServices}"
  67. fi
  68. }
  69. runDockerCommand()
  70. {
  71. validCommands=(start stop restart pull build ps logs)
  72. if [[ ${validCommands[*]} =~ (^|[[:space:]])"$2"($|[[:space:]]) ]]; then
  73. servicesString=$(handleServices "backend frontend mongo redis" "${@:3}")
  74. if [[ ${servicesString:0:1} == 1 ]]; then
  75. if [[ ${servicesString:2:4} == "all" ]]; then
  76. servicesString=""
  77. else
  78. servicesString=${servicesString:2}
  79. fi
  80. if [[ ${2} == "stop" || ${2} == "restart" ]]; then
  81. # shellcheck disable=SC2086
  82. ${dockerCompose} stop ${servicesString}
  83. fi
  84. if [[ ${2} == "start" || ${2} == "restart" ]]; then
  85. # shellcheck disable=SC2086
  86. ${dockerCompose} up -d ${servicesString}
  87. fi
  88. if [[ ${2} == "pull" || ${2} == "build" || ${2} == "ps" || ${2} == "logs" ]]; then
  89. # shellcheck disable=SC2086
  90. ${dockerCompose} "${2}" ${servicesString}
  91. fi
  92. exitValue=$?
  93. if [[ ${exitValue} -gt 0 ]]; then
  94. exit ${exitValue}
  95. fi
  96. else
  97. echo -e "${RED}${servicesString:2}\n${YELLOW}Usage: ${1} [backend, frontend, mongo, redis]${NC}"
  98. exit 1
  99. fi
  100. else
  101. echo -e "${RED}Error: Invalid runDockerCommand input${NC}"
  102. exit 1
  103. fi
  104. }
  105. getContainerId()
  106. {
  107. if [[ ${DOCKER_COMMAND} == "docker" ]]; then
  108. containerId=$(${dockerCompose} ps -q "${1}")
  109. else
  110. containerId=$(${dockerCompose} ps | sed '0,/CONTAINER/d' | awk "/${1}/ {print \$1;exit}")
  111. fi
  112. echo "${containerId}"
  113. }
  114. case $1 in
  115. start)
  116. echo -e "${CYAN}Musare | Start Services${NC}"
  117. # shellcheck disable=SC2068
  118. runDockerCommand "$(basename "$0") $1" start ${@:2}
  119. ;;
  120. stop)
  121. echo -e "${CYAN}Musare | Stop Services${NC}"
  122. # shellcheck disable=SC2068
  123. runDockerCommand "$(basename "$0") $1" stop ${@:2}
  124. ;;
  125. restart)
  126. echo -e "${CYAN}Musare | Restart Services${NC}"
  127. # shellcheck disable=SC2068
  128. runDockerCommand "$(basename "$0") $1" restart ${@:2}
  129. ;;
  130. build)
  131. echo -e "${CYAN}Musare | Build Services${NC}"
  132. # shellcheck disable=SC2068
  133. runDockerCommand "$(basename "$0") $1" pull ${@:2}
  134. # shellcheck disable=SC2068
  135. runDockerCommand "$(basename "$0") $1" build ${@:2}
  136. ;;
  137. status)
  138. echo -e "${CYAN}Musare | Service Status${NC}"
  139. # shellcheck disable=SC2068
  140. runDockerCommand "$(basename "$0") $1" ps ${@:2}
  141. ;;
  142. reset)
  143. echo -e "${CYAN}Musare | Reset Services${NC}"
  144. servicesString=$(handleServices "backend frontend mongo redis" "${@:2}")
  145. if [[ ${servicesString:0:1} == 1 && ${servicesString:2:4} == "all" ]]; then
  146. echo -e "${RED}Resetting will remove the ${REDIS_DATA_LOCATION} and ${MONGO_DATA_LOCATION} directories.${NC}"
  147. echo -e "${GREEN}Are you sure you want to reset all data? ${YELLOW}[y,n]: ${NC}"
  148. read -r confirm
  149. if [[ "${confirm}" == y* ]]; then
  150. runDockerCommand "$(basename "$0") $1" stop
  151. ${dockerCompose} rm -v --force
  152. if [[ -d $REDIS_DATA_LOCATION ]]; then
  153. rm -rf "${REDIS_DATA_LOCATION}"
  154. fi
  155. if [[ -d $MONGO_DATA_LOCATION ]]; then
  156. rm -rf "${MONGO_DATA_LOCATION}"
  157. fi
  158. else
  159. echo -e "${RED}Cancelled reset${NC}"
  160. fi
  161. elif [[ ${servicesString:0:1} == 1 ]]; then
  162. if [[ "${servicesString:2}" == *redis* && "${servicesString:2}" == *mongo* ]]; then
  163. echo -e "${RED}Resetting will remove the ${REDIS_DATA_LOCATION} and ${MONGO_DATA_LOCATION} directories.${NC}"
  164. elif [[ "${servicesString:2}" == *redis* ]]; then
  165. echo -e "${RED}Resetting will remove the ${REDIS_DATA_LOCATION} directory.${NC}"
  166. elif [[ "${servicesString:2}" == *mongo* ]]; then
  167. echo -e "${RED}Resetting will remove the ${MONGO_DATA_LOCATION} directory.${NC}"
  168. fi
  169. echo -e "${GREEN}Are you sure you want to reset all data for $(echo "${servicesString:2}" | tr ' ' ',')? ${YELLOW}[y,n]: ${NC}"
  170. read -r confirm
  171. if [[ "${confirm}" == y* ]]; then
  172. # shellcheck disable=SC2086
  173. runDockerCommand "$(basename "$0") $1" stop ${servicesString:2}
  174. # shellcheck disable=SC2086
  175. ${dockerCompose} rm -v --force ${servicesString}
  176. if [[ "${servicesString:2}" == *redis* && -d $REDIS_DATA_LOCATION ]]; then
  177. rm -rf "${REDIS_DATA_LOCATION}"
  178. fi
  179. if [[ "${servicesString:2}" == *mongo* && -d $MONGO_DATA_LOCATION ]]; then
  180. rm -rf "${MONGO_DATA_LOCATION}"
  181. fi
  182. else
  183. echo -e "${RED}Cancelled reset${NC}"
  184. fi
  185. else
  186. echo -e "${RED}${servicesString:2}\n${YELLOW}Usage: $(basename "$0") build [backend, frontend, mongo, redis]${NC}"
  187. exit 1
  188. fi
  189. ;;
  190. attach)
  191. echo -e "${CYAN}Musare | Attach${NC}"
  192. if [[ $2 == "backend" ]]; then
  193. containerId=$(getContainerId backend)
  194. if [[ -z $containerId ]]; then
  195. echo -e "${RED}Error: Backend offline, please start to attach.${NC}"
  196. exit 1
  197. else
  198. echo -e "${YELLOW}Detach with CTRL+P+Q${NC}"
  199. ${docker} attach "$containerId"
  200. fi
  201. elif [[ $2 == "mongo" ]]; then
  202. MONGO_VERSION_INT=${MONGO_VERSION:0:1}
  203. if [[ -z $(getContainerId mongo) ]]; then
  204. echo -e "${RED}Error: Mongo offline, please start to attach.${NC}"
  205. exit 1
  206. else
  207. echo -e "${YELLOW}Detach with CTRL+D${NC}"
  208. if [[ $MONGO_VERSION_INT -ge 5 ]]; then
  209. ${dockerCompose} exec mongo mongosh musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "disableTelemetry()" --shell
  210. else
  211. ${dockerCompose} exec mongo mongo musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}"
  212. fi
  213. fi
  214. elif [[ $2 == "redis" ]]; then
  215. if [[ -z $(getContainerId redis) ]]; then
  216. echo -e "${RED}Error: Redis offline, please start to attach.${NC}"
  217. exit 1
  218. else
  219. echo -e "${YELLOW}Detach with CTRL+C${NC}"
  220. ${dockerCompose} exec redis redis-cli -a "${REDIS_PASSWORD}"
  221. fi
  222. else
  223. echo -e "${RED}Invalid service $2\n${YELLOW}Usage: $(basename "$0") attach [backend,mongo,redis]${NC}"
  224. exit 1
  225. fi
  226. ;;
  227. lint|eslint)
  228. echo -e "${CYAN}Musare | Lint${NC}"
  229. services=$(sed "s/\(\ \)\{0,1\}\(-\)\{0,2\}fix//g;t;q1" <<< "${@:2}")
  230. fixFound=$?
  231. if [[ $fixFound -eq 0 ]]; then
  232. fix="--fix"
  233. echo -e "${GREEN}Auto-fix enabled${NC}"
  234. fi
  235. services=$(sed "s/\(\ \)\{0,1\}\(-\)\{0,2\}no-cache//g;t;q1" <<< "${services}")
  236. noCacheFound=$?
  237. cache="--cache"
  238. if [[ $noCacheFound -eq 0 ]]; then
  239. cache=""
  240. echo -e "${YELLOW}ESlint cache disabled${NC}"
  241. fi
  242. # shellcheck disable=SC2068
  243. servicesString=$(handleServices "backend frontend docs" ${services[@]})
  244. if [[ ${servicesString:0:1} == 1 ]]; then
  245. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *frontend* ]]; then
  246. echo -e "${CYAN}Running frontend lint...${NC}"
  247. ${dockerCompose} exec -T frontend npx eslint $cache src --ext .js,.ts,.vue $fix
  248. frontendExitValue=$?
  249. fi
  250. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *backend* ]]; then
  251. echo -e "${CYAN}Running backend lint...${NC}"
  252. ${dockerCompose} exec -T backend npx eslint $cache logic $fix
  253. backendExitValue=$?
  254. fi
  255. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *docs* ]]; then
  256. echo -e "${CYAN}Running docs lint...${NC}"
  257. ${docker} run -v "${scriptLocation}":/workdir ghcr.io/igorshubovych/markdownlint-cli:latest ".wiki" "*.md" $fix
  258. docsExitValue=$?
  259. fi
  260. if [[ ${frontendExitValue} -gt 0 || ${backendExitValue} -gt 0 || ${docsExitValue} -gt 0 ]]; then
  261. exitValue=1
  262. else
  263. exitValue=0
  264. fi
  265. else
  266. echo -e "${RED}${servicesString:2}\n${YELLOW}Usage: $(basename "$0") lint [backend, frontend, docs] [fix]${NC}"
  267. exitValue=1
  268. fi
  269. if [[ ${exitValue} -gt 0 ]]; then
  270. exit ${exitValue}
  271. fi
  272. ;;
  273. typescript|ts)
  274. echo -e "${CYAN}Musare | TypeScript Check${NC}"
  275. servicesString=$(handleServices "backend frontend" "${@:2}")
  276. if [[ ${servicesString:0:1} == 1 ]]; then
  277. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *frontend* ]]; then
  278. echo -e "${CYAN}Running frontend typescript check...${NC}"
  279. ${dockerCompose} exec -T frontend npm run typescript
  280. frontendExitValue=$?
  281. fi
  282. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *backend* ]]; then
  283. echo -e "${CYAN}Running backend typescript check...${NC}"
  284. ${dockerCompose} exec -T backend npm run typescript
  285. backendExitValue=$?
  286. fi
  287. if [[ ${frontendExitValue} -gt 0 || ${backendExitValue} -gt 0 ]]; then
  288. exitValue=1
  289. else
  290. exitValue=0
  291. fi
  292. else
  293. echo -e "${RED}${servicesString:2}\n${YELLOW}Usage: $(basename "$0") typescript [backend, frontend]${NC}"
  294. exitValue=1
  295. fi
  296. if [[ ${exitValue} -gt 0 ]]; then
  297. exit ${exitValue}
  298. fi
  299. ;;
  300. update)
  301. echo -e "${CYAN}Musare | Update${NC}"
  302. git fetch
  303. exitValue=$?
  304. if [[ ${exitValue} -gt 0 ]]; then
  305. exit ${exitValue}
  306. fi
  307. if [[ $(git rev-parse HEAD) == $(git rev-parse @\{u\}) ]]; then
  308. echo -e "${GREEN}Already up to date${NC}"
  309. else
  310. dbChange=$(git log --name-only --oneline HEAD..origin/"$(git rev-parse --abbrev-ref HEAD)" | grep "backend/logic/db/schemas")
  311. fcChange=$(git log --name-only --oneline HEAD..origin/"$(git rev-parse --abbrev-ref HEAD)" | grep "frontend/dist/config/template.json")
  312. bcChange=$(git log --name-only --oneline HEAD..origin/"$(git rev-parse --abbrev-ref HEAD)" | grep "backend/config/template.json")
  313. if [[ ( $2 == "auto" && -z $dbChange && -z $fcChange && -z $bcChange ) || -z $2 ]]; then
  314. echo -e "${CYAN}Updating...${NC}"
  315. git pull
  316. exitValue=$?
  317. if [[ ${exitValue} -gt 0 ]]; then
  318. exit ${exitValue}
  319. fi
  320. runDockerCommand "$(basename "$0") $1" build
  321. runDockerCommand "$(basename "$0") $1" restart
  322. echo -e "${GREEN}Updated!${NC}"
  323. if [[ -n $dbChange ]]; then
  324. echo -e "${RED}Database schema has changed, please run migration!${NC}"
  325. fi
  326. if [[ -n $fcChange ]]; then
  327. echo -e "${RED}Frontend config has changed, please update!${NC}"
  328. fi
  329. if [[ -n $bcChange ]]; then
  330. echo -e "${RED}Backend config has changed, please update!${NC}"
  331. fi
  332. elif [[ $2 == "auto" ]]; then
  333. echo -e "${RED}Auto Update Failed! Database and/or config has changed!${NC}"
  334. exit 1
  335. fi
  336. fi
  337. ;;
  338. logs)
  339. echo -e "${CYAN}Musare | Logs${NC}"
  340. # shellcheck disable=SC2068
  341. runDockerCommand "$(basename "$0") $1" logs ${@:2}
  342. ;;
  343. backup)
  344. echo -e "${CYAN}Musare | Backup${NC}"
  345. if [[ -z "${BACKUP_LOCATION}" ]]; then
  346. backupLocation="${scriptLocation%x}/backups"
  347. else
  348. backupLocation="${BACKUP_LOCATION%/}"
  349. fi
  350. if [[ ! -d "${backupLocation}" ]]; then
  351. echo -e "${YELLOW}Creating backup directory at ${backupLocation}${NC}"
  352. mkdir "${backupLocation}"
  353. fi
  354. if [[ -z "${BACKUP_NAME}" ]]; then
  355. backupLocation="${backupLocation}/musare-$(date +"%Y-%m-%d-%s").dump"
  356. else
  357. backupLocation="${backupLocation}/${BACKUP_NAME}"
  358. fi
  359. echo -e "${YELLOW}Creating backup at ${backupLocation}${NC}"
  360. ${dockerCompose} exec -T mongo sh -c "mongodump --authenticationDatabase musare -u ${MONGO_USER_USERNAME} -p ${MONGO_USER_PASSWORD} -d musare --archive" > "${backupLocation}"
  361. ;;
  362. restore)
  363. echo -e "${CYAN}Musare | Restore${NC}"
  364. if [[ -z $2 ]]; then
  365. echo -e "${GREEN}Please enter the full path of the dump you wish to restore: ${NC}"
  366. read -r restoreFile
  367. else
  368. restoreFile=$2
  369. fi
  370. if [[ -z ${restoreFile} ]]; then
  371. echo -e "${RED}Error: no restore path given, cancelled restoration.${NC}"
  372. exit 1
  373. elif [[ -d ${restoreFile} ]]; then
  374. echo -e "${RED}Error: restore path given is a directory, cancelled restoration.${NC}"
  375. exit 1
  376. elif [[ ! -f ${restoreFile} ]]; then
  377. echo -e "${RED}Error: no file at restore path given, cancelled restoration.${NC}"
  378. exit 1
  379. else
  380. ${dockerCompose} exec -T mongo sh -c "mongorestore --authenticationDatabase musare -u ${MONGO_USER_USERNAME} -p ${MONGO_USER_PASSWORD} --archive" < "${restoreFile}"
  381. fi
  382. ;;
  383. admin)
  384. echo -e "${CYAN}Musare | Add Admin${NC}"
  385. MONGO_VERSION_INT=${MONGO_VERSION:0:1}
  386. if [[ $2 == "add" ]]; then
  387. if [[ -z $3 ]]; then
  388. echo -e "${GREEN}Please enter the username of the user you wish to make an admin: ${NC}"
  389. read -r adminUser
  390. else
  391. adminUser=$3
  392. fi
  393. if [[ -z $adminUser ]]; then
  394. echo -e "${RED}Error: Username for new admin not provided.${NC}"
  395. exit 1
  396. else
  397. if [[ $MONGO_VERSION_INT -ge 5 ]]; then
  398. ${dockerCompose} exec mongo mongosh musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "disableTelemetry(); db.users.updateOne({username: '${adminUser}'}, {\$set: {role: 'admin'}})"
  399. else
  400. ${dockerCompose} exec mongo mongo musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "db.users.updateOne({username: '${adminUser}'}, {\$set: {role: 'admin'}})"
  401. fi
  402. fi
  403. elif [[ $2 == "remove" ]]; then
  404. if [[ -z $3 ]]; then
  405. echo -e "${GREEN}Please enter the username of the user you wish to remove as admin: ${NC}"
  406. read -r adminUser
  407. else
  408. adminUser=$3
  409. fi
  410. if [[ -z $adminUser ]]; then
  411. echo -e "${RED}Error: Username for new admin not provided.${NC}"
  412. exit 1
  413. else
  414. if [[ $MONGO_VERSION_INT -ge 5 ]]; then
  415. ${dockerCompose} exec mongo mongosh musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "disableTelemetry(); db.users.updateOne({username: '${adminUser}'}, {\$set: {role: 'default'}})"
  416. else
  417. ${dockerCompose} exec mongo mongo musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "db.users.updateOne({username: '${adminUser}'}, {\$set: {role: 'default'}})"
  418. fi
  419. fi
  420. else
  421. echo -e "${RED}Invalid command $2\n${YELLOW}Usage: $(basename "$0") admin [add,remove] username${NC}"
  422. exit 1
  423. fi
  424. ;;
  425. "")
  426. echo -e "${CYAN}Musare | Available Commands${NC}"
  427. echo -e "${YELLOW}start - Start services${NC}"
  428. echo -e "${YELLOW}stop - Stop services${NC}"
  429. echo -e "${YELLOW}restart - Restart services${NC}"
  430. echo -e "${YELLOW}status - Service status${NC}"
  431. echo -e "${YELLOW}logs - View logs for services${NC}"
  432. echo -e "${YELLOW}update - Update Musare${NC}"
  433. echo -e "${YELLOW}attach [backend,mongo,redis] - Attach to backend service, mongo or redis shell${NC}"
  434. echo -e "${YELLOW}build - Build services${NC}"
  435. echo -e "${YELLOW}lint - Run lint on frontend, backend and/or docs${NC}"
  436. echo -e "${YELLOW}backup - Backup database data to file${NC}"
  437. echo -e "${YELLOW}restore - Restore database data from backup file${NC}"
  438. echo -e "${YELLOW}reset - Reset service data${NC}"
  439. echo -e "${YELLOW}admin [add,remove] - Assign/unassign admin role to/from a user${NC}"
  440. echo -e "${YELLOW}typescript - Run typescript checks on frontend and/or backend${NC}"
  441. ;;
  442. *)
  443. echo -e "${CYAN}Musare${NC}"
  444. echo -e "${RED}Error: Invalid Command $1${NC}"
  445. echo -e "${CYAN}Available Commands:${NC}"
  446. echo -e "${YELLOW}start - Start services${NC}"
  447. echo -e "${YELLOW}stop - Stop services${NC}"
  448. echo -e "${YELLOW}restart - Restart services${NC}"
  449. echo -e "${YELLOW}status - Service status${NC}"
  450. echo -e "${YELLOW}logs - View logs for services${NC}"
  451. echo -e "${YELLOW}update - Update Musare${NC}"
  452. echo -e "${YELLOW}attach [backend,mongo,redis] - Attach to backend service, mongo or redis shell${NC}"
  453. echo -e "${YELLOW}build - Build services${NC}"
  454. echo -e "${YELLOW}lint - Run lint on frontend, backend and/or docs${NC}"
  455. echo -e "${YELLOW}backup - Backup database data to file${NC}"
  456. echo -e "${YELLOW}restore - Restore database data from backup file${NC}"
  457. echo -e "${YELLOW}reset - Reset service data${NC}"
  458. echo -e "${YELLOW}admin [add,remove] - Assign/unassign admin role to/from a user${NC}"
  459. echo -e "${YELLOW}typescript - Run typescript checks on frontend and/or backend${NC}"
  460. exit 1
  461. ;;
  462. esac