musare.sh 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. #!/bin/bash
  2. set -e
  3. export PATH=/usr/local/bin:/usr/bin:/bin
  4. # Color variables
  5. CYAN='\033[33;36m';
  6. RED='\033[0;31m'
  7. YELLOW='\033[0;93m'
  8. GREEN='\033[0;32m'
  9. NC='\033[0m'
  10. # Print provided formatted error and exit with code (default 1)
  11. throw()
  12. {
  13. echo -e "${RED}${1}${NC}"
  14. exit "${2:-1}"
  15. }
  16. # Navigate to repository
  17. scriptLocation=$(dirname -- "$(readlink -fn -- "$0"; echo x)")
  18. cd "${scriptLocation%x}"
  19. # Import environment variables
  20. if [[ ! -f .env ]]; then
  21. throw "Error: .env does not exist" 2
  22. fi
  23. # shellcheck disable=SC1091
  24. source .env
  25. # Define docker command
  26. docker="${DOCKER_COMMAND:-docker}"
  27. if [[ ${docker} != "docker" && ${docker} != "podman" ]]; then
  28. throw "Error: Invalid DOCKER_COMMAND"
  29. fi
  30. set +e
  31. # Check if docker is installed
  32. ${docker} --version > /dev/null 2>&1
  33. dockerInstalled=$?
  34. # Define docker compose command
  35. dockerCompose="${docker} compose"
  36. # Check if docker compose is installed
  37. ${dockerCompose} version > /dev/null 2>&1
  38. composeInstalled=$?
  39. if [[ ${composeInstalled} -gt 0 ]]; then
  40. dockerCompose="${docker}-compose"
  41. ${dockerCompose} --version > /dev/null 2>&1
  42. composeInstalled=$?
  43. fi
  44. set -e
  45. # Exit if docker and/or docker compose is not installed
  46. if [[ ${dockerInstalled} -gt 0 || ${composeInstalled} -gt 0 ]]; then
  47. if [[ ${dockerInstalled} -eq 0 && ${composeInstalled} -gt 0 ]]; then
  48. throw "Error: ${dockerCompose} not installed."
  49. fi
  50. if [[ ${dockerInstalled} -gt 0 && ${composeInstalled} -eq 0 ]]; then
  51. throw "Error: ${docker} not installed."
  52. fi
  53. throw "Error: ${docker} and ${dockerCompose} not installed."
  54. fi
  55. # Add docker compose file arguments to command
  56. composeFiles="-f docker-compose.yml"
  57. if [[ ${APP_ENV} == "development" ]]; then
  58. composeFiles="${composeFiles} -f docker-compose.dev.yml"
  59. fi
  60. if [[ -f docker-compose.override.yml ]]; then
  61. composeFiles="${composeFiles} -f docker-compose.override.yml"
  62. fi
  63. dockerCompose="${dockerCompose} ${composeFiles}"
  64. # Parse services from arguments string
  65. handleServices()
  66. {
  67. # shellcheck disable=SC2206
  68. validServices=($1)
  69. servicesArray=()
  70. invalidServices=false
  71. for x in "${@:2}"; do
  72. if [[ ${validServices[*]} =~ (^|[[:space:]])"$x"($|[[:space:]]) ]]; then
  73. if ! [[ ${servicesArray[*]} =~ (^|[[:space:]])"$x"($|[[:space:]]) ]]; then
  74. servicesArray+=("${x}")
  75. fi
  76. else
  77. if [[ $invalidServices == false ]]; then
  78. invalidServices="${x}"
  79. else
  80. invalidServices="${invalidServices} ${x}"
  81. fi
  82. fi
  83. done
  84. if [[ $invalidServices == false && ${#servicesArray[@]} -gt 0 ]]; then
  85. echo "1|${servicesArray[*]}"
  86. elif [[ $invalidServices == false ]]; then
  87. echo "1|all"
  88. else
  89. echo "0|Invalid Service(s): ${invalidServices}"
  90. fi
  91. }
  92. # Execute a docker command
  93. runDockerCommand()
  94. {
  95. validCommands=(start stop restart pull build ps logs)
  96. if ! [[ ${validCommands[*]} =~ (^|[[:space:]])"$2"($|[[:space:]]) ]]; then
  97. throw "Error: Invalid runDockerCommand input"
  98. fi
  99. servicesString=$(handleServices "backend frontend mongo redis" "${@:3}")
  100. if [[ ${servicesString:0:1} != 1 ]]; then
  101. throw "${servicesString:2}\n${YELLOW}Usage: ${1} [backend, frontend, mongo, redis]"
  102. fi
  103. if [[ ${servicesString:2:4} == "all" ]]; then
  104. servicesString=""
  105. pullServices="mongo redis"
  106. buildServices="backend frontend"
  107. else
  108. servicesString=${servicesString:2}
  109. pullArray=()
  110. buildArray=()
  111. if [[ "${servicesString}" == *mongo* ]]; then
  112. pullArray+=("mongo")
  113. fi
  114. if [[ "${servicesString}" == *redis* ]]; then
  115. pullArray+=("redis")
  116. fi
  117. if [[ "${servicesString}" == *backend* ]]; then
  118. buildArray+=("backend")
  119. fi
  120. if [[ "${servicesString}" == *frontend* ]]; then
  121. buildArray+=("frontend")
  122. fi
  123. pullServices="${pullArray[*]}"
  124. buildServices="${buildArray[*]}"
  125. fi
  126. if [[ ${2} == "stop" || ${2} == "restart" ]]; then
  127. # shellcheck disable=SC2086
  128. ${dockerCompose} stop ${servicesString}
  129. fi
  130. if [[ ${2} == "start" || ${2} == "restart" ]]; then
  131. # shellcheck disable=SC2086
  132. ${dockerCompose} up -d ${servicesString}
  133. fi
  134. if [[ ${2} == "pull" && ${pullServices} != "" ]]; then
  135. # shellcheck disable=SC2086
  136. ${dockerCompose} pull ${pullServices}
  137. fi
  138. if [[ ${2} == "build" && ${buildServices} != "" ]]; then
  139. # shellcheck disable=SC2086
  140. ${dockerCompose} build ${buildServices}
  141. fi
  142. if [[ ${2} == "ps" || ${2} == "logs" ]]; then
  143. # shellcheck disable=SC2086
  144. ${dockerCompose} "${2}" ${servicesString}
  145. fi
  146. }
  147. # Get docker container id
  148. getContainerId()
  149. {
  150. if [[ $docker == "docker" ]]; then
  151. containerId=$(${dockerCompose} ps -q "${1}")
  152. else
  153. containerId=$(${dockerCompose} ps \
  154. | sed '0,/CONTAINER/d' \
  155. | awk "/${1}/ {print \$1;exit}")
  156. fi
  157. echo "${containerId}"
  158. }
  159. # Reset services
  160. handleReset()
  161. {
  162. servicesString=$(handleServices "backend frontend mongo redis" "${@:2}")
  163. if [[ ${servicesString:0:1} != 1 ]]; then
  164. throw "${servicesString:2}\n${YELLOW}Usage: ${1} [backend, frontend, mongo, redis]"
  165. fi
  166. if [[ ${servicesString:2:4} == "all" ]]; then
  167. echo -e "${RED}Resetting will remove the ${REDIS_DATA_LOCATION} and ${MONGO_DATA_LOCATION} directories.${NC}"
  168. echo -e "${GREEN}Are you sure you want to reset all data? ${YELLOW}[y,n]: ${NC}"
  169. else
  170. if [[ "${servicesString:2}" == *redis* && "${servicesString:2}" == *mongo* ]]; then
  171. echo -e "${RED}Resetting will remove the ${REDIS_DATA_LOCATION} and ${MONGO_DATA_LOCATION} directories.${NC}"
  172. elif [[ "${servicesString:2}" == *redis* ]]; then
  173. echo -e "${RED}Resetting will remove the ${REDIS_DATA_LOCATION} directory.${NC}"
  174. elif [[ "${servicesString:2}" == *mongo* ]]; then
  175. echo -e "${RED}Resetting will remove the ${MONGO_DATA_LOCATION} directory.${NC}"
  176. fi
  177. echo -e "${GREEN}Are you sure you want to reset all data for $(echo "${servicesString:2}" | tr ' ' ',')? ${YELLOW}[y,n]: ${NC}"
  178. fi
  179. read -r confirm
  180. if [[ "${confirm}" != y* ]]; then
  181. throw "Cancelled reset"
  182. fi
  183. if [[ ${servicesString:2:4} == "all" ]]; then
  184. runDockerCommand "$(basename "$0") $1" stop
  185. ${dockerCompose} rm -v --force
  186. if [[ -d $REDIS_DATA_LOCATION ]]; then
  187. rm -rf "${REDIS_DATA_LOCATION}"
  188. fi
  189. if [[ -d $MONGO_DATA_LOCATION ]]; then
  190. rm -rf "${MONGO_DATA_LOCATION}"
  191. fi
  192. else
  193. # shellcheck disable=SC2086
  194. runDockerCommand "$(basename "$0") $1" stop ${servicesString:2}
  195. # shellcheck disable=SC2086
  196. ${dockerCompose} rm -v --force ${servicesString:2}
  197. if [[ "${servicesString:2}" == *redis* && -d $REDIS_DATA_LOCATION ]]; then
  198. rm -rf "${REDIS_DATA_LOCATION}"
  199. fi
  200. if [[ "${servicesString:2}" == *mongo* && -d $MONGO_DATA_LOCATION ]]; then
  201. rm -rf "${MONGO_DATA_LOCATION}"
  202. fi
  203. fi
  204. }
  205. # Attach to service in docker container
  206. attachContainer()
  207. {
  208. containerId=$(getContainerId "${2}")
  209. if [[ -z $containerId ]]; then
  210. throw "Error: ${2} offline, please start to attach."
  211. fi
  212. case $2 in
  213. backend)
  214. echo -e "${YELLOW}Detach with CTRL+P+Q${NC}"
  215. ${docker} attach "$containerId"
  216. ;;
  217. mongo)
  218. MONGO_VERSION_INT=${MONGO_VERSION:0:1}
  219. echo -e "${YELLOW}Detach with CTRL+D${NC}"
  220. if [[ $MONGO_VERSION_INT -ge 5 ]]; then
  221. ${dockerCompose} exec mongo mongosh musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "disableTelemetry()" --shell
  222. else
  223. ${dockerCompose} exec mongo mongo musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}"
  224. fi
  225. ;;
  226. redis)
  227. echo -e "${YELLOW}Detach with CTRL+C${NC}"
  228. ${dockerCompose} exec redis redis-cli -a "${REDIS_PASSWORD}"
  229. ;;
  230. *)
  231. throw "Invalid service ${2}\n${YELLOW}Usage: ${1} [backend, mongo, redis]"
  232. ;;
  233. esac
  234. }
  235. # Lint codebase, docs, scripts, etc
  236. handleLinting()
  237. {
  238. set +e
  239. # shellcheck disable=SC2001
  240. services=$(sed "s/\(\ \)\{0,1\}\(-\)\{0,2\}fix//g;t;q1" <<< "${@:2}")
  241. fixFound=$?
  242. if [[ $fixFound -eq 0 ]]; then
  243. fix="--fix"
  244. echo -e "${GREEN}Auto-fix enabled${NC}"
  245. fi
  246. # shellcheck disable=SC2001
  247. services=$(sed "s/\(\ \)\{0,1\}\(-\)\{0,2\}no-cache//g;t;q1" <<< "${services}")
  248. noCacheFound=$?
  249. cache="--cache"
  250. if [[ $noCacheFound -eq 0 ]]; then
  251. cache=""
  252. echo -e "${YELLOW}ESlint cache disabled${NC}"
  253. fi
  254. set -e
  255. # shellcheck disable=SC2068
  256. servicesString=$(handleServices "backend frontend docs shell" ${services[@]})
  257. if [[ ${servicesString:0:1} != 1 ]]; then
  258. throw "${servicesString:2}\n${YELLOW}Usage: ${1} [backend, frontend, docs, shell] [fix]"
  259. fi
  260. set +e
  261. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *frontend* ]]; then
  262. echo -e "${CYAN}Running frontend lint...${NC}"
  263. ${dockerCompose} exec -T frontend npm run lint -- "${cache}" "${fix}"
  264. frontendExitValue=$?
  265. fi
  266. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *backend* ]]; then
  267. echo -e "${CYAN}Running backend lint...${NC}"
  268. ${dockerCompose} exec -T backend npm run lint -- "${cache}" "${fix}"
  269. backendExitValue=$?
  270. fi
  271. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *docs* ]]; then
  272. echo -e "${CYAN}Running docs lint...${NC}"
  273. ${docker} run --rm -v "${scriptLocation}":/workdir ghcr.io/igorshubovych/markdownlint-cli:latest ".wiki" "*.md" "${fix}"
  274. docsExitValue=$?
  275. fi
  276. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *shell* ]]; then
  277. echo -e "${CYAN}Running shell lint...${NC}"
  278. ${docker} run --rm -v "${scriptLocation}":/mnt koalaman/shellcheck:stable ./*.sh ./**/*.sh
  279. shellExitValue=$?
  280. fi
  281. set -e
  282. if [[ ${frontendExitValue} -gt 0 || ${backendExitValue} -gt 0 || ${docsExitValue} -gt 0 || ${shellExitValue} -gt 0 ]]; then
  283. exit 1
  284. fi
  285. }
  286. # Validate typescript in services
  287. handleTypescript()
  288. {
  289. set +e
  290. # shellcheck disable=SC2001
  291. services=$(sed "s/\(\ \)\{0,1\}\(-\)\{0,2\}strict//g;t;q1" <<< "${@:2}")
  292. strictFound=$?
  293. if [[ $strictFound -eq 0 ]]; then
  294. strict="--strict"
  295. echo -e "${GREEN}Strict mode enabled${NC}"
  296. fi
  297. set -e
  298. # shellcheck disable=SC2068
  299. servicesString=$(handleServices "backend frontend" ${services[@]})
  300. if [[ ${servicesString:0:1} != 1 ]]; then
  301. throw "${servicesString:2}\n${YELLOW}Usage: ${1} [backend, frontend] [strict]"
  302. fi
  303. set +e
  304. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *frontend* ]]; then
  305. echo -e "${CYAN}Running frontend typescript check...${NC}"
  306. ${dockerCompose} exec -T frontend npm run typescript -- "${strict}"
  307. frontendExitValue=$?
  308. fi
  309. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *backend* ]]; then
  310. echo -e "${CYAN}Running backend typescript check...${NC}"
  311. ${dockerCompose} exec -T backend npm run typescript -- "${strict}"
  312. backendExitValue=$?
  313. fi
  314. set -e
  315. if [[ ${frontendExitValue} -gt 0 || ${backendExitValue} -gt 0 ]]; then
  316. exit 1
  317. fi
  318. }
  319. # Execute automated tests in services
  320. handleTests()
  321. {
  322. # shellcheck disable=SC2068
  323. servicesString=$(handleServices "backend frontend" ${services[@]})
  324. if [[ ${servicesString:0:1} != 1 ]]; then
  325. throw "${servicesString:2}\n${YELLOW}Usage: ${1} [backend, frontend]"
  326. fi
  327. set +e
  328. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *backend* ]]; then
  329. echo -e "${CYAN}Running backend tests...${NC}"
  330. ${dockerCompose} exec -T backend npm run test
  331. backendExitValue=$?
  332. fi
  333. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *frontend* ]]; then
  334. echo -e "${CYAN}Running frontend tests...${NC}"
  335. ${dockerCompose} exec -T frontend npm run test -- --run
  336. frontendExitValue=$?
  337. fi
  338. set -e
  339. if [[ ${backendExitValue} -gt 0 || ${frontendExitValue} -gt 0 ]]; then
  340. exit 1
  341. fi
  342. }
  343. # Execute test coverage in services
  344. handleTestCoverage()
  345. {
  346. servicesString=$(handleServices "frontend" "${@:2}")
  347. if [[ ${servicesString:0:1} != 1 ]]; then
  348. throw "${servicesString:2}\n${YELLOW}Usage: ${1} [frontend]"
  349. fi
  350. set +e
  351. if [[ ${servicesString:2:4} == "all" || "${servicesString:2}" == *frontend* ]]; then
  352. echo -e "${CYAN}Running frontend test coverage report...${NC}"
  353. ${dockerCompose} exec -T frontend npm run coverage
  354. frontendExitValue=$?
  355. fi
  356. set -e
  357. if [[ ${frontendExitValue} -gt 0 ]]; then
  358. exit 1
  359. fi
  360. }
  361. # Update Musare
  362. handleUpdate()
  363. {
  364. musareshModified=$(git diff HEAD -- musare.sh)
  365. git fetch
  366. updated=$(git log --name-only --oneline HEAD..@\{u\})
  367. if [[ ${updated} == "" ]]; then
  368. echo -e "${GREEN}Already up to date${NC}"
  369. exit 0
  370. fi
  371. breakingConfigChange=$(git rev-list "$(git rev-parse HEAD)" | grep d8b73be1de231821db34c677110b7b97e413451f)
  372. if [[ -f backend/config/default.json && -z $breakingConfigChange ]]; then
  373. throw "Configuration has breaking changes. Please rename or remove 'backend/config/default.json' and run the update command again to continue."
  374. fi
  375. musareshChange=$(echo "${updated}" | grep "musare.sh")
  376. dbChange=$(echo "${updated}" | grep "backend/logic/db/schemas")
  377. bcChange=$(echo "${updated}" | grep "backend/config/default.json")
  378. if [[ ( $2 == "auto" && -z $dbChange && -z $bcChange && -z $musareshChange ) || -z $2 ]]; then
  379. if [[ -n $musareshChange && $(git diff @\{u\} -- musare.sh) != "" ]]; then
  380. if [[ $musareshModified != "" ]]; then
  381. throw "musare.sh has been modified, please reset these changes and run the update command again to continue."
  382. else
  383. git checkout @\{u\} -- musare.sh
  384. throw "${YELLOW}musare.sh has been updated, please run the update command again to continue."
  385. fi
  386. else
  387. git pull
  388. echo -e "${CYAN}Updating...${NC}"
  389. runDockerCommand "$(basename "$0") $1" pull
  390. runDockerCommand "$(basename "$0") $1" build
  391. runDockerCommand "$(basename "$0") $1" restart
  392. echo -e "${GREEN}Updated!${NC}"
  393. if [[ -n $dbChange ]]; then
  394. echo -e "${RED}Database schema has changed, please run migration!${NC}"
  395. fi
  396. if [[ -n $bcChange ]]; then
  397. echo -e "${RED}Backend config has changed, please update!${NC}"
  398. fi
  399. fi
  400. elif [[ $2 == "auto" ]]; then
  401. throw "Auto Update Failed! musare.sh, database and/or config has changed!"
  402. fi
  403. }
  404. # Backup the database
  405. handleBackup()
  406. {
  407. if [[ -z "${BACKUP_LOCATION}" ]]; then
  408. backupLocation="${scriptLocation%x}/backups"
  409. else
  410. backupLocation="${BACKUP_LOCATION%/}"
  411. fi
  412. if [[ ! -d "${backupLocation}" ]]; then
  413. echo -e "${YELLOW}Creating backup directory at ${backupLocation}${NC}"
  414. mkdir "${backupLocation}"
  415. fi
  416. if [[ -z "${BACKUP_NAME}" ]]; then
  417. backupLocation="${backupLocation}/musare-$(date +"%Y-%m-%d-%s").dump"
  418. else
  419. backupLocation="${backupLocation}/${BACKUP_NAME}"
  420. fi
  421. echo -e "${YELLOW}Creating backup at ${backupLocation}${NC}"
  422. ${dockerCompose} exec -T mongo sh -c "mongodump --authenticationDatabase musare -u ${MONGO_USER_USERNAME} -p ${MONGO_USER_PASSWORD} -d musare --archive" > "${backupLocation}"
  423. }
  424. # Restore database from dump
  425. handleRestore()
  426. {
  427. if [[ -z $2 ]]; then
  428. echo -e "${GREEN}Please enter the full path of the dump you wish to restore: ${NC}"
  429. read -r restoreFile
  430. else
  431. restoreFile=$2
  432. fi
  433. if [[ -z ${restoreFile} ]]; then
  434. throw "Error: no restore path given, cancelled restoration."
  435. elif [[ -d ${restoreFile} ]]; then
  436. throw "Error: restore path given is a directory, cancelled restoration."
  437. elif [[ ! -f ${restoreFile} ]]; then
  438. throw "Error: no file at restore path given, cancelled restoration."
  439. else
  440. ${dockerCompose} exec -T mongo sh -c "mongorestore --authenticationDatabase musare -u ${MONGO_USER_USERNAME} -p ${MONGO_USER_PASSWORD} --archive" < "${restoreFile}"
  441. fi
  442. }
  443. # Toggle user admin role
  444. handleAdmin()
  445. {
  446. MONGO_VERSION_INT=${MONGO_VERSION:0:1}
  447. case $2 in
  448. add)
  449. if [[ -z $3 ]]; then
  450. echo -e "${GREEN}Please enter the username of the user you wish to make an admin: ${NC}"
  451. read -r adminUser
  452. else
  453. adminUser=$3
  454. fi
  455. if [[ -z $adminUser ]]; then
  456. throw "Error: Username for new admin not provided."
  457. fi
  458. if [[ $MONGO_VERSION_INT -ge 5 ]]; then
  459. ${dockerCompose} exec mongo mongosh musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "disableTelemetry(); db.users.updateOne({username: '${adminUser}'}, {\$set: {role: 'admin'}})"
  460. else
  461. ${dockerCompose} exec mongo mongo musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "db.users.updateOne({username: '${adminUser}'}, {\$set: {role: 'admin'}})"
  462. fi
  463. ;;
  464. remove)
  465. if [[ -z $3 ]]; then
  466. echo -e "${GREEN}Please enter the username of the user you wish to remove as admin: ${NC}"
  467. read -r adminUser
  468. else
  469. adminUser=$3
  470. fi
  471. if [[ -z $adminUser ]]; then
  472. throw "Error: Username for new admin not provided."
  473. fi
  474. if [[ $MONGO_VERSION_INT -ge 5 ]]; then
  475. ${dockerCompose} exec mongo mongosh musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "disableTelemetry(); db.users.updateOne({username: '${adminUser}'}, {\$set: {role: 'default'}})"
  476. else
  477. ${dockerCompose} exec mongo mongo musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "db.users.updateOne({username: '${adminUser}'}, {\$set: {role: 'default'}})"
  478. fi
  479. ;;
  480. *)
  481. throw "Invalid command $2\n${YELLOW}Usage: ${1} [add,remove] username"
  482. ;;
  483. esac
  484. }
  485. availableCommands=$(cat << COMMANDS
  486. start - Start services
  487. stop - Stop services
  488. restart - Restart services
  489. status - Service status
  490. logs - View logs for services
  491. update - Update Musare
  492. attach [backend,mongo,redis] - Attach to backend service, mongo or redis shell
  493. build - Build services
  494. lint - Run lint on frontend, backend, docs and/or shell
  495. backup - Backup database data to file
  496. restore - Restore database data from backup file
  497. reset - Reset service data
  498. admin [add,remove] - Assign/unassign admin role to/from a user
  499. typescript - Run typescript checks on frontend and/or backend
  500. COMMANDS
  501. )
  502. # Handle command
  503. case $1 in
  504. start)
  505. echo -e "${CYAN}Musare | Start Services${NC}"
  506. # shellcheck disable=SC2068
  507. runDockerCommand "$(basename "$0") $1" start ${@:2}
  508. ;;
  509. stop)
  510. echo -e "${CYAN}Musare | Stop Services${NC}"
  511. # shellcheck disable=SC2068
  512. runDockerCommand "$(basename "$0") $1" stop ${@:2}
  513. ;;
  514. restart)
  515. echo -e "${CYAN}Musare | Restart Services${NC}"
  516. # shellcheck disable=SC2068
  517. runDockerCommand "$(basename "$0") $1" restart ${@:2}
  518. ;;
  519. build)
  520. echo -e "${CYAN}Musare | Build Services${NC}"
  521. # shellcheck disable=SC2068
  522. runDockerCommand "$(basename "$0") $1" pull ${@:2}
  523. # shellcheck disable=SC2068
  524. runDockerCommand "$(basename "$0") $1" build ${@:2}
  525. ;;
  526. status)
  527. echo -e "${CYAN}Musare | Service Status${NC}"
  528. # shellcheck disable=SC2068
  529. runDockerCommand "$(basename "$0") $1" ps ${@:2}
  530. ;;
  531. reset)
  532. echo -e "${CYAN}Musare | Reset Services${NC}"
  533. # shellcheck disable=SC2068
  534. handleReset "$(basename "$0") $1" ${@:2}
  535. ;;
  536. attach)
  537. echo -e "${CYAN}Musare | Attach${NC}"
  538. attachContainer "$(basename "$0") $1" "$2"
  539. ;;
  540. lint|eslint)
  541. echo -e "${CYAN}Musare | Lint${NC}"
  542. # shellcheck disable=SC2068
  543. handleLinting "$(basename "$0") $1" ${@:2}
  544. ;;
  545. typescript|ts)
  546. echo -e "${CYAN}Musare | TypeScript Check${NC}"
  547. # shellcheck disable=SC2068
  548. handleTypescript "$(basename "$0") $1" ${@:2}
  549. ;;
  550. test)
  551. echo -e "${CYAN}Musare | Test${NC}"
  552. # shellcheck disable=SC2068
  553. handleTests "$(basename "$0") $1" ${@:2}
  554. ;;
  555. test:coverage)
  556. echo -e "${CYAN}Musare | Test Coverage${NC}"
  557. # shellcheck disable=SC2068
  558. handleTestCoverage "$(basename "$0") $1" ${@:2}
  559. ;;
  560. update)
  561. echo -e "${CYAN}Musare | Update${NC}"
  562. # shellcheck disable=SC2068
  563. handleUpdate "$(basename "$0") $1" ${@:2}
  564. ;;
  565. logs)
  566. echo -e "${CYAN}Musare | Logs${NC}"
  567. # shellcheck disable=SC2068
  568. runDockerCommand "$(basename "$0") $1" logs ${@:2}
  569. ;;
  570. backup)
  571. echo -e "${CYAN}Musare | Backup${NC}"
  572. # shellcheck disable=SC2068
  573. handleBackup "$(basename "$0") $1" ${@:2}
  574. ;;
  575. restore)
  576. echo -e "${CYAN}Musare | Restore${NC}"
  577. # shellcheck disable=SC2068
  578. handleRestore "$(basename "$0") $1" ${@:2}
  579. ;;
  580. admin)
  581. echo -e "${CYAN}Musare | Add Admin${NC}"
  582. # shellcheck disable=SC2068
  583. handleAdmin "$(basename "$0") $1" ${@:2}
  584. ;;
  585. "")
  586. echo -e "${CYAN}Musare | Available Commands${NC}"
  587. echo -e "${YELLOW}${availableCommands}${NC}"
  588. ;;
  589. *)
  590. echo -e "${CYAN}Musare${NC}"
  591. echo -e "${RED}Error: Invalid Command $1${NC}"
  592. echo -e "${CYAN}Available Commands:${NC}"
  593. echo -e "${YELLOW}${availableCommands}${NC}"
  594. exit 1
  595. ;;
  596. esac