Просмотр исходного кода

Merge pull request #5720 from weseek/master

Release v5.0.2
Yuki Takei 4 лет назад
Родитель
Сommit
6b43c8bbc8

+ 1 - 1
lerna.json

@@ -1,7 +1,7 @@
 {
   "npmClient": "yarn",
   "useWorkspaces": true,
-  "version": "5.0.1",
+  "version": "5.0.2-RC.0",
   "packages": [
     "packages/*"
   ]

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "5.0.1",
+  "version": "5.0.2-RC.0",
   "description": "Team collaboration software using markdown",
   "tags": [
     "wiki",

+ 7 - 7
packages/app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/app",
-  "version": "5.0.1",
+  "version": "5.0.2-RC.0",
   "license": "MIT",
   "scripts": {
     "//// for production": "",
@@ -62,11 +62,11 @@
     "@elastic/elasticsearch7": "npm:@elastic/elasticsearch@^7.17.0",
     "@godaddy/terminus": "^4.9.0",
     "@google-cloud/storage": "^5.8.5",
-    "@growi/codemirror-textlint": "^5.0.1",
-    "@growi/plugin-attachment-refs": "^5.0.1",
-    "@growi/plugin-lsx": "^5.0.1",
-    "@growi/plugin-pukiwiki-like-linker": "^5.0.1",
-    "@growi/slack": "^5.0.1",
+    "@growi/codemirror-textlint": "^5.0.2-RC.0",
+    "@growi/plugin-attachment-refs": "^5.0.2-RC.0",
+    "@growi/plugin-lsx": "^5.0.2-RC.0",
+    "@growi/plugin-pukiwiki-like-linker": "^5.0.2-RC.0",
+    "@growi/slack": "^5.0.2-RC.0",
     "@promster/express": "^7.0.2",
     "@promster/server": "^7.0.4",
     "@slack/events-api": "^3.0.0",
@@ -167,7 +167,7 @@
   },
   "devDependencies": {
     "@alienfast/i18next-loader": "^1.1.4",
-    "@growi/ui": "^5.0.1",
+    "@growi/ui": "^5.0.2-RC.0",
     "@handsontable/react": "=2.1.0",
     "@types/compression": "^1.7.0",
     "@types/express": "^4.17.11",

+ 4 - 3
packages/app/src/components/Navbar/PageEditorModeManager.jsx

@@ -1,4 +1,5 @@
 import React, { useCallback } from 'react';
+
 import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
 import { UncontrolledTooltip } from 'reactstrap';
@@ -50,13 +51,13 @@ function PageEditorModeManager(props) {
   const showHackmdBtn = isHackmdEnabled || isAdmin;
 
   const pageEditorModeButtonClickedHandler = useCallback((viewType) => {
-    if (isBtnDisabled || !isHackmdEnabled) {
+    if (isBtnDisabled) {
       return;
     }
     if (onPageEditorModeButtonClicked != null) {
       onPageEditorModeButtonClicked(viewType);
     }
-  }, [isBtnDisabled, isHackmdEnabled, onPageEditorModeButtonClicked]);
+  }, [isBtnDisabled, onPageEditorModeButtonClicked]);
 
   return (
     <>
@@ -91,7 +92,7 @@ function PageEditorModeManager(props) {
             <PageEditorModeButtonWrapper
               editorMode={editorMode}
               isBtnDisabled={isBtnDisabled || !isHackmdEnabled}
-              onClick={pageEditorModeButtonClickedHandler}
+              onClick={isHackmdEnabled ? pageEditorModeButtonClickedHandler : undefined}
               targetMode={EditorMode.HackMD}
               icon={<i className="fa fa-file-text-o" />}
               label={t('hackmd.hack_md')}

+ 0 - 89
packages/app/src/components/ShareLink/ShareLinkList.jsx

@@ -1,89 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-
-import { withTranslation } from 'react-i18next';
-import dateFnsFormat from 'date-fns/format';
-
-import { withUnstatedContainers } from '../UnstatedUtils';
-
-import AppContainer from '~/client/services/AppContainer';
-import CopyDropdown from '../Page/CopyDropdown';
-
-const ShareLinkList = (props) => {
-
-  const { t } = props;
-  function deleteLinkHandler(shareLinkId) {
-    if (props.onClickDeleteButton == null) {
-      return;
-    }
-    props.onClickDeleteButton(shareLinkId);
-  }
-
-  function renderShareLinks() {
-    return (
-      <>
-        {props.shareLinks.map(shareLink => (
-          <tr key={shareLink._id}>
-            <td>
-              <div className="d-flex">
-                <span className="mr-auto my-auto">{shareLink._id}</span>
-                <CopyDropdown
-                  pagePath={shareLink.relatedPage.path}
-                  dropdownToggleId={`copydropdown-${shareLink._id}`}
-                  pageId={shareLink._id}
-                  isShareLinkMode
-                >
-                  Copy Link
-                </CopyDropdown>
-              </div>
-            </td>
-            {props.isAdmin && <td><a href={shareLink.relatedPage.path}>{shareLink.relatedPage.path}</a></td>}
-            <td>{shareLink.expiredAt && <span>{dateFnsFormat(new Date(shareLink.expiredAt), 'yyyy-MM-dd HH:mm')}</span>}</td>
-            <td>{shareLink.description}</td>
-            <td>
-              <button className="btn btn-outline-warning" type="button" onClick={() => deleteLinkHandler(shareLink._id)}>
-                <i className="icon-trash"></i>{t('Delete')}
-              </button>
-            </td>
-          </tr>
-        ))}
-      </>
-    );
-  }
-
-  return (
-    <div className="table-responsive">
-      <table className="table table-bordered">
-        <thead>
-          <tr>
-            <th>{t('share_links.Share Link')}</th>
-            {props.isAdmin && <th>{t('share_links.Page Path')}</th>}
-            <th>{t('share_links.expire')}</th>
-            <th>{t('share_links.description')}</th>
-            <th></th>
-          </tr>
-        </thead>
-        <tbody>
-          {renderShareLinks()}
-        </tbody>
-      </table>
-    </div>
-  );
-};
-
-/**
- * Wrapper component for using unstated
- */
-const ShareLinkListWrapper = withUnstatedContainers(ShareLinkList, [AppContainer]);
-
-ShareLinkList.propTypes = {
-  t: PropTypes.func.isRequired, //  i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-
-  shareLinks: PropTypes.array.isRequired,
-  onClickDeleteButton: PropTypes.func,
-  isAdmin: PropTypes.bool,
-};
-
-export default withTranslation()(ShareLinkListWrapper);

+ 113 - 0
packages/app/src/components/ShareLink/ShareLinkList.tsx

@@ -0,0 +1,113 @@
+import React from 'react';
+
+import dateFnsFormat from 'date-fns/format';
+import { useTranslation } from 'react-i18next';
+
+import CopyDropdown from '../Page/CopyDropdown';
+
+
+type ShareLinkTrProps = {
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  shareLink: any,
+  isAdmin?: boolean,
+  onDelete?: () => void,
+}
+
+const ShareLinkTr = (props: ShareLinkTrProps): JSX.Element => {
+  const { t } = useTranslation();
+
+  const { isAdmin, shareLink, onDelete } = props;
+
+  const { _id: shareLinkId, relatedPage } = shareLink;
+
+  const isRelatedPageExists = relatedPage != null;
+
+  return (
+    <tr key={shareLinkId}>
+      <td>
+        <div className="d-flex">
+          <span className="mr-auto my-auto">{shareLinkId}</span>
+
+          { isRelatedPageExists && (
+            <CopyDropdown
+              pagePath={relatedPage.path}
+              dropdownToggleId={`copydropdown-${shareLinkId}`}
+              pageId={shareLinkId}
+              isShareLinkMode
+            >
+              Copy Link
+            </CopyDropdown>
+          ) }
+        </div>
+      </td>
+      { isAdmin && (
+        <td>
+          { isRelatedPageExists
+            ? <a href={relatedPage.path}>{relatedPage.path}</a>
+            : '(Page is not found)'
+          }
+        </td>
+      ) }
+      <td>{shareLink.expiredAt && <span>{dateFnsFormat(new Date(shareLink.expiredAt), 'yyyy-MM-dd HH:mm')}</span>}</td>
+      <td>{shareLink.description}</td>
+      <td>
+        <button className="btn btn-outline-warning" type="button" onClick={onDelete}>
+          <i className="icon-trash"></i>{t('Delete')}
+        </button>
+      </td>
+    </tr>
+  );
+};
+
+
+type Props = {
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  shareLinks: any[],
+  onClickDeleteButton?: (shareLinkId: string) => void,
+  isAdmin?: boolean,
+}
+
+const ShareLinkList = (props: Props): JSX.Element => {
+
+  const { t } = useTranslation();
+
+  function renderShareLinks() {
+    return (
+      <>
+        {props.shareLinks.map(shareLink => (
+          <ShareLinkTr
+            isAdmin={props.isAdmin}
+            shareLink={shareLink}
+            onDelete={() => {
+              if (props.onClickDeleteButton == null) {
+                return;
+              }
+              props.onClickDeleteButton(shareLink._id);
+            }}
+          />
+        ))}
+      </>
+    );
+  }
+
+  return (
+    <div className="table-responsive">
+      <table className="table table-bordered">
+        <thead>
+          <tr>
+            <th>{t('share_links.Share Link')}</th>
+            {props.isAdmin && <th>{t('share_links.Page Path')}</th>}
+            <th>{t('share_links.expire')}</th>
+            <th>{t('share_links.description')}</th>
+            <th></th>
+          </tr>
+        </thead>
+        <tbody>
+          {renderShareLinks()}
+        </tbody>
+      </table>
+    </div>
+  );
+};
+
+export default ShareLinkList;

+ 12 - 8
packages/app/src/server/routes/apiv3/share-links.js

@@ -249,21 +249,25 @@ module.exports = (crowi) => {
   */
   router.delete('/:id', loginRequired, csrf, validator.deleteShareLink, apiV3FormValidator, async(req, res) => {
     const { id } = req.params;
+    const { user } = req;
 
     try {
-      const deletedShareLink = await ShareLink.findOne({ _id: id });
+      const shareLinkToDelete = await ShareLink.findOne({ _id: id });
 
       // check permission
-      const page = await Page.findByIdAndViewer(deletedShareLink.relatedPage, req.user);
-      if (page == null) {
-        const msg = 'Page is not found or forbidden';
-        logger.error('Error', msg);
-        return res.apiv3Err(new ErrorV3(msg, 'delete-shareLink-failed'));
+      if (!user.isAdmin) {
+        const page = await Page.findByIdAndViewer(shareLinkToDelete.relatedPage, user);
+        const isPageExists = (await Page.count({ _id: shareLinkToDelete.relatedPage }) > 0);
+        if (page == null && isPageExists) {
+          const msg = 'Page is not found or forbidden';
+          logger.error('Error', msg);
+          return res.apiv3Err(new ErrorV3(msg, 'delete-shareLink-failed'));
+        }
       }
 
       // remove
-      await deletedShareLink.remove();
-      return res.apiv3({ deletedShareLink });
+      await shareLinkToDelete.remove();
+      return res.apiv3({ deletedShareLink: shareLinkToDelete });
     }
     catch (err) {
       const msg = 'Error occurred in delete share link';

+ 1 - 1
packages/codemirror-textlint/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/codemirror-textlint",
-  "version": "5.0.1",
+  "version": "5.0.2-RC.0",
   "license": "MIT",
   "main": "dist/index.js",
   "scripts": {

+ 1 - 1
packages/core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/core",
-  "version": "5.0.1",
+  "version": "5.0.2-RC.0",
   "description": "GROWI Core Libraries",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/plugin-attachment-refs/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/plugin-attachment-refs",
-  "version": "5.0.1",
+  "version": "5.0.2-RC.0",
   "description": "GROWI Plugin to add ref/refimg/refs/refsimg tags",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/plugin-lsx/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/plugin-lsx",
-  "version": "5.0.1",
+  "version": "5.0.2-RC.0",
   "description": "GROWI plugin to list pages",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/plugin-pukiwiki-like-linker/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/plugin-pukiwiki-like-linker",
-  "version": "5.0.1",
+  "version": "5.0.2-RC.0",
   "description": "GROWI plugin to add PukiwikiLikeLinker",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/slack/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/slack",
-  "version": "5.0.1",
+  "version": "5.0.2-RC.0",
   "license": "MIT",
   "main": "dist/index.js",
   "typings": "dist/index.d.ts",

+ 2 - 2
packages/slackbot-proxy/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/slackbot-proxy",
-  "version": "5.0.1",
+  "version": "5.0.2-slackbot-proxy.0",
   "license": "MIT",
   "scripts": {
     "build": "yarn tsc && tsc-alias -p tsconfig.build.json",
@@ -25,7 +25,7 @@
   },
   "dependencies": {
     "@godaddy/terminus": "^4.9.0",
-    "@growi/slack": "^5.0.1",
+    "@growi/slack": "^5.0.2-RC.0",
     "@slack/oauth": "^2.0.1",
     "@slack/web-api": "^6.2.4",
     "@tsed/common": "^6.43.0",

+ 1 - 1
packages/ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/ui",
-  "version": "5.0.1",
+  "version": "5.0.2-RC.0",
   "description": "GROWI UI Libraries",
   "license": "MIT",
   "keywords": [