AdminUsersContainer.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. import { isServer } from '@growi/core/dist/utils';
  2. import { debounce } from 'throttle-debounce';
  3. import { Container } from 'unstated';
  4. import {
  5. apiv3Delete,
  6. apiv3Get,
  7. apiv3Post,
  8. apiv3Put,
  9. } from '../util/apiv3-client';
  10. /**
  11. * Service container for admin users page (Users.jsx)
  12. * @extends {Container} unstated Container
  13. */
  14. export default class AdminUsersContainer extends Container {
  15. constructor(appContainer) {
  16. super();
  17. if (isServer()) {
  18. return;
  19. }
  20. this.appContainer = appContainer;
  21. this.state = {
  22. users: [],
  23. sort: 'id',
  24. sortOrder: 'asc',
  25. isPasswordResetModalShown: false,
  26. isUserInviteModalShown: false,
  27. userForPasswordResetModal: null,
  28. totalUsers: 0,
  29. activePage: 1,
  30. pagingLimit: Infinity,
  31. selectedStatusList: new Set(['all']),
  32. searchText: '',
  33. userStatistics: null,
  34. };
  35. this.showPasswordResetModal = this.showPasswordResetModal.bind(this);
  36. this.hidePasswordResetModal = this.hidePasswordResetModal.bind(this);
  37. this.toggleUserInviteModal = this.toggleUserInviteModal.bind(this);
  38. this.handleChangeSearchTextDebouce = debounce(3000, () =>
  39. this.retrieveUsersByPagingNum(1),
  40. );
  41. }
  42. /**
  43. * Workaround for the mangling in production build to break constructor.name
  44. */
  45. static getClassName() {
  46. return 'AdminUsersContainer';
  47. }
  48. /**
  49. * Workaround for status list
  50. */
  51. isSelected(statusType) {
  52. return this.state.selectedStatusList.has(statusType);
  53. }
  54. handleClick(statusType) {
  55. const all = 'all';
  56. if (this.isSelected(statusType)) {
  57. this.deleteStatusFromList(statusType);
  58. } else {
  59. if (statusType === all) {
  60. this.clearStatusList();
  61. } else {
  62. this.deleteStatusFromList(all);
  63. }
  64. this.addStatusToList(statusType);
  65. }
  66. }
  67. async clearStatusList() {
  68. const { selectedStatusList } = this.state;
  69. selectedStatusList.clear();
  70. await this.setState({ selectedStatusList });
  71. }
  72. async addStatusToList(statusType) {
  73. const { selectedStatusList } = this.state;
  74. selectedStatusList.add(statusType);
  75. await this.setState({ selectedStatusList });
  76. this.retrieveUsersByPagingNum(1);
  77. }
  78. async deleteStatusFromList(statusType) {
  79. const { selectedStatusList } = this.state;
  80. selectedStatusList.delete(statusType);
  81. await this.setState({ selectedStatusList });
  82. this.retrieveUsersByPagingNum(1);
  83. }
  84. /**
  85. * Workaround for Increment Search Text Input
  86. */
  87. async handleChangeSearchText(searchText) {
  88. await this.setState({ searchText });
  89. this.handleChangeSearchTextDebouce();
  90. }
  91. async clearSearchText() {
  92. await this.setState({ searchText: '' });
  93. this.retrieveUsersByPagingNum(1);
  94. }
  95. /**
  96. * Workaround for Sorting
  97. */
  98. async sort(sort, isAsc) {
  99. const sortOrder = isAsc ? 'asc' : 'desc';
  100. await this.setState({ sort, sortOrder });
  101. this.retrieveUsersByPagingNum(1);
  102. }
  103. async resetAllChanges() {
  104. await this.setState({
  105. sort: 'id',
  106. sortOrder: 'asc',
  107. searchText: '',
  108. selectedStatusList: new Set(['all']),
  109. });
  110. this.retrieveUsersByPagingNum(1);
  111. }
  112. /**
  113. * syncUsers of selectedPage
  114. * @memberOf AdminUsersContainer
  115. * @param {number} selectedPage
  116. */
  117. async retrieveUsersByPagingNum(selectedPage) {
  118. const params = {
  119. page: selectedPage,
  120. sort: this.state.sort,
  121. sortOrder: this.state.sortOrder,
  122. selectedStatusList: Array.from(this.state.selectedStatusList),
  123. searchText: this.state.searchText,
  124. // Even if email is hidden, it will be displayed on admin page.
  125. forceIncludeAttributes: ['email'],
  126. };
  127. const { data } = await apiv3Get('/users', params);
  128. if (data.paginateResult == null) {
  129. throw new Error("data must conclude 'paginateResult' property.");
  130. }
  131. const {
  132. docs: users,
  133. totalDocs: totalUsers,
  134. limit: pagingLimit,
  135. } = data.paginateResult;
  136. this.setState({
  137. users,
  138. totalUsers,
  139. pagingLimit,
  140. activePage: selectedPage,
  141. });
  142. }
  143. /**
  144. * retrieve user statistics
  145. */
  146. async retrieveUserStatistics() {
  147. const statsRes = await apiv3Get('/statistics/user');
  148. const userStatistics = statsRes.data.data;
  149. this.setState({ userStatistics });
  150. }
  151. /**
  152. * create user invited
  153. * @memberOf AdminUsersContainer
  154. * @param {object} shapedEmailList
  155. * @param {bool} sendEmail
  156. */
  157. async createUserInvited(shapedEmailList, sendEmail) {
  158. const response = await apiv3Post('/users/invite', {
  159. shapedEmailList,
  160. sendEmail,
  161. });
  162. await this.retrieveUsersByPagingNum(this.state.activePage);
  163. return response.data;
  164. }
  165. /**
  166. * open reset password modal, and props user
  167. * @memberOf AdminUsersContainer
  168. * @param {object} user
  169. */
  170. async showPasswordResetModal(user) {
  171. await this.setState({
  172. isPasswordResetModalShown: true,
  173. userForPasswordResetModal: user,
  174. });
  175. }
  176. /**
  177. * close reset password modal
  178. * @memberOf AdminUsersContainer
  179. */
  180. async hidePasswordResetModal() {
  181. await this.setState({
  182. isPasswordResetModalShown: false,
  183. userForPasswordResetModal: null,
  184. });
  185. }
  186. /**
  187. * toggle user invite modal
  188. * @memberOf AdminUsersContainer
  189. */
  190. async toggleUserInviteModal() {
  191. await this.setState({
  192. isUserInviteModalShown: !this.state.isUserInviteModalShown,
  193. });
  194. }
  195. /**
  196. * Grant user admin
  197. * @memberOf AdminUsersContainer
  198. * @param {string} userId
  199. * @return {string} username
  200. */
  201. async grantUserAdmin(userId) {
  202. const response = await apiv3Put(`/users/${userId}/grant-admin`);
  203. const { username } = response.data.userData;
  204. await this.retrieveUsersByPagingNum(this.state.activePage);
  205. return username;
  206. }
  207. /**
  208. * Revoke user admin
  209. * @memberOf AdminUsersContainer
  210. * @param {string} userId
  211. * @return {string} username
  212. */
  213. async revokeUserAdmin(userId) {
  214. const response = await apiv3Put(`/users/${userId}/revoke-admin`);
  215. const { username } = response.data.userData;
  216. await this.retrieveUsersByPagingNum(this.state.activePage);
  217. return username;
  218. }
  219. /**
  220. * Grant user read only access
  221. * @memberOf AdminUsersContainer
  222. * @param {string} userId
  223. * @return {string} username
  224. */
  225. async grantUserReadOnly(userId) {
  226. const response = await apiv3Put(`/users/${userId}/grant-read-only`);
  227. const { username } = response.data.userData;
  228. await this.retrieveUsersByPagingNum(this.state.activePage);
  229. return username;
  230. }
  231. /**
  232. * Revoke user read only access
  233. * @memberOf AdminUsersContainer
  234. * @param {string} userId
  235. * @return {string} username
  236. */
  237. async revokeUserReadOnly(userId) {
  238. const response = await apiv3Put(`/users/${userId}/revoke-read-only`);
  239. const { username } = response.data.userData;
  240. await this.retrieveUsersByPagingNum(this.state.activePage);
  241. return username;
  242. }
  243. /**
  244. * Activate user
  245. * @memberOf AdminUsersContainer
  246. * @param {string} userId
  247. * @return {string} username
  248. */
  249. async activateUser(userId) {
  250. const response = await apiv3Put(`/users/${userId}/activate`);
  251. const { username } = response.data.userData;
  252. await this.retrieveUsersByPagingNum(this.state.activePage);
  253. return username;
  254. }
  255. /**
  256. * Deactivate user
  257. * @memberOf AdminUsersContainer
  258. * @param {string} userId
  259. * @return {string} username
  260. */
  261. async deactivateUser(userId) {
  262. const response = await apiv3Put(`/users/${userId}/deactivate`);
  263. const { username } = response.data.userData;
  264. await this.retrieveUsersByPagingNum(this.state.activePage);
  265. return username;
  266. }
  267. /**
  268. * remove user
  269. * @memberOf AdminUsersContainer
  270. * @param {string} userId
  271. * @return {object} removedUserData
  272. */
  273. async removeUser(userId) {
  274. const response = await apiv3Delete(`/users/${userId}/remove`);
  275. const removedUserData = response.data.userData;
  276. await this.retrieveUsersByPagingNum(this.state.activePage);
  277. return removedUserData;
  278. }
  279. }