page-operation.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import { SubscriptionStatusType, Nullable } from '@growi/core';
  2. import urljoin from 'url-join';
  3. import { OptionsToSave } from '~/interfaces/editor-settings';
  4. import loggerFactory from '~/utils/logger';
  5. import { toastError } from '../util/apiNotification';
  6. import { apiPost } from '../util/apiv1-client';
  7. import { apiv3Post, apiv3Put } from '../util/apiv3-client';
  8. const logger = loggerFactory('growi:services:page-operation');
  9. export const toggleSubscribe = async(pageId: string, currentStatus: SubscriptionStatusType | undefined): Promise<void> => {
  10. try {
  11. const newStatus = currentStatus === SubscriptionStatusType.SUBSCRIBE
  12. ? SubscriptionStatusType.UNSUBSCRIBE
  13. : SubscriptionStatusType.SUBSCRIBE;
  14. await apiv3Put('/page/subscribe', { pageId, status: newStatus });
  15. }
  16. catch (err) {
  17. toastError(err);
  18. }
  19. };
  20. export const toggleLike = async(pageId: string, currentValue?: boolean): Promise<void> => {
  21. try {
  22. await apiv3Put('/page/likes', { pageId, bool: !currentValue });
  23. }
  24. catch (err) {
  25. toastError(err);
  26. }
  27. };
  28. export const toggleBookmark = async(pageId: string, currentValue?: boolean): Promise<void> => {
  29. try {
  30. await apiv3Put('/bookmarks', { pageId, bool: !currentValue });
  31. }
  32. catch (err) {
  33. toastError(err);
  34. }
  35. };
  36. export const updateContentWidth = async(pageId: string, newValue: boolean): Promise<void> => {
  37. try {
  38. await apiv3Put(`/page/${pageId}/content-width`, { expandContentWidth: newValue });
  39. }
  40. catch (err) {
  41. toastError(err);
  42. }
  43. };
  44. export const bookmark = async(pageId: string): Promise<void> => {
  45. try {
  46. await apiv3Put('/bookmarks', { pageId, bool: true });
  47. }
  48. catch (err) {
  49. toastError(err);
  50. }
  51. };
  52. export const unbookmark = async(pageId: string): Promise<void> => {
  53. try {
  54. await apiv3Put('/bookmarks', { pageId, bool: false });
  55. }
  56. catch (err) {
  57. toastError(err);
  58. }
  59. };
  60. export const exportAsMarkdown = (pageId: string, revisionId: string, format: string): void => {
  61. const url = new URL(urljoin(window.location.origin, '_api/v3/page/export', pageId));
  62. url.searchParams.append('format', format);
  63. url.searchParams.append('revisionId', revisionId);
  64. window.location.href = url.href;
  65. };
  66. /**
  67. * send request to fix broken paths caused by unexpected events such as server shutdown while renaming page paths
  68. */
  69. export const resumeRenameOperation = async(pageId: string): Promise<void> => {
  70. await apiv3Post('/pages/resume-rename', { pageId });
  71. };
  72. // TODO: define return type
  73. const createPage = async(pagePath: string, markdown: string, tmpParams: OptionsToSave) => {
  74. // clone
  75. const params = Object.assign(tmpParams, {
  76. path: pagePath,
  77. body: markdown,
  78. });
  79. const res = await apiv3Post('/pages/', params);
  80. const { page, tags, revision } = res.data;
  81. return { page, tags, revision };
  82. };
  83. // TODO: define return type
  84. const updatePage = async(pageId: string, revisionId: string, markdown: string, tmpParams: OptionsToSave) => {
  85. // clone
  86. const params = Object.assign(tmpParams, {
  87. page_id: pageId,
  88. revision_id: revisionId,
  89. body: markdown,
  90. });
  91. const res: any = await apiPost('/pages.update', params);
  92. if (!res.ok) {
  93. throw new Error(res.error);
  94. }
  95. return res;
  96. };
  97. type PageInfo= {
  98. path: string,
  99. pageId: Nullable<string>,
  100. revisionId: Nullable<string>,
  101. }
  102. // TODO: define return type
  103. export const saveOrUpdate = async(optionsToSave: OptionsToSave, pageInfo: PageInfo, markdown: string) => {
  104. const { path, pageId, revisionId } = pageInfo;
  105. const options = Object.assign({}, optionsToSave);
  106. /*
  107. * Note: variable "markdown" will be received from params
  108. * please delete the following code after implemating HackMD editor function
  109. */
  110. // let markdown;
  111. // if (editorMode === EditorMode.HackMD) {
  112. // const pageEditorByHackmd = this.appContainer.getComponentInstance('PageEditorByHackmd');
  113. // markdown = await pageEditorByHackmd.getMarkdown();
  114. // // set option to sync
  115. // options.isSyncRevisionToHackmd = true;
  116. // revisionId = this.state.revisionIdHackmdSynced;
  117. // }
  118. // else {
  119. // const pageEditor = this.appContainer.getComponentInstance('PageEditor');
  120. // const pageEditor = getComponentInstance('PageEditor');
  121. // markdown = pageEditor.getMarkdown();
  122. // }
  123. const isNoRevisionPage = pageId != null && revisionId == null;
  124. let res;
  125. if (pageId == null || isNoRevisionPage) {
  126. res = await createPage(path, markdown, options);
  127. }
  128. else {
  129. if (revisionId == null) {
  130. const msg = '\'revisionId\' is required to update page';
  131. throw new Error(msg);
  132. }
  133. res = await updatePage(pageId, revisionId, markdown, options);
  134. }
  135. return res;
  136. };