Explorar el Código

Merge pull request #1886 from weseek/support/create-sub-navigation-for-user-page

Support/create sub navigation for user page
Yuki Takei hace 6 años
padre
commit
2882ae7e67

+ 2 - 0
src/client/js/app.jsx

@@ -35,6 +35,7 @@ import CommentContainer from './services/CommentContainer';
 import EditorContainer from './services/EditorContainer';
 import EditorContainer from './services/EditorContainer';
 import TagContainer from './services/TagContainer';
 import TagContainer from './services/TagContainer';
 import GrowiSubNavigation from './components/Navbar/GrowiSubNavigation';
 import GrowiSubNavigation from './components/Navbar/GrowiSubNavigation';
+import GrowiSubNavigationForUserPage from './components/Navbar/GrowiSubNavigationForUserPage';
 import PersonalContainer from './services/PersonalContainer';
 import PersonalContainer from './services/PersonalContainer';
 
 
 import { appContainer, componentMappings } from './bootstrap';
 import { appContainer, componentMappings } from './bootstrap';
@@ -101,6 +102,7 @@ if (pageContainer.state.path != null) {
     'revision-path': <RevisionPath behaviorType={appContainer.config.behaviorType} pageId={pageContainer.state.pageId} pagePath={pageContainer.state.path} />,
     'revision-path': <RevisionPath behaviorType={appContainer.config.behaviorType} pageId={pageContainer.state.pageId} pagePath={pageContainer.state.path} />,
     'tag-label': <TagLabels />,
     'tag-label': <TagLabels />,
     'grw-subnav': <GrowiSubNavigation />,
     'grw-subnav': <GrowiSubNavigation />,
+    'grw-subnav-for-user-page': <GrowiSubNavigationForUserPage />,
   });
   });
 }
 }
 
 

+ 83 - 0
src/client/js/components/Navbar/GrowiSubNavigationForUserPage.jsx

@@ -0,0 +1,83 @@
+import React, { useState, useEffect } from 'react';
+import PropTypes from 'prop-types';
+
+import { withTranslation } from 'react-i18next';
+import { throttle } from 'throttle-debounce';
+
+import { createSubscribedElement } from '../UnstatedUtils';
+import AppContainer from '../../services/AppContainer';
+import RevisionPath from '../Page/RevisionPath';
+import PageContainer from '../../services/PageContainer';
+import BookmarkButton from '../BookmarkButton';
+import UserPicture from '../User/UserPicture';
+
+const GrowiSubNavigationForUserPage = (props) => {
+  const pageUser = JSON.parse(document.querySelector('#grw-subnav-for-user-page').getAttribute('data-page-user'));
+  const { appContainer, pageContainer } = props;
+  const { pageId } = pageContainer.state;
+  const [isCompactMode, setIsCompactMode] = useState(false);
+  const scrollAmountForFixed = 175;
+  const layoutType = appContainer.getConfig().layoutType;
+
+  useEffect(() => {
+    window.addEventListener('scroll', throttle(300, () => {
+      setIsCompactMode(window.pageYOffset > scrollAmountForFixed);
+    }));
+  }, []);
+
+  return (
+    <div className={(isCompactMode && layoutType === 'growi') && 'fixed-top grw-compact-subnavbar px-3'}>
+
+      {/* Page Path */}
+      <h4>
+        <RevisionPath behaviorType={appContainer.config.behaviorType} pageId={pageId} pagePath={pageContainer.state.path} />
+      </h4>
+
+      <div className="d-flex">
+        <div className="users-info d-flex align-items-center mr-auto">
+          <UserPicture user={pageUser} />
+
+          <div className="users-meta">
+            <div className="d-flex align-items-center">
+              <h1>
+                {pageUser.name}
+              </h1>
+            </div>
+            <div className="user-page-meta">
+              <ul>
+                <li className="user-page-username"><i className="icon-user mr-1"></i>{pageUser.username}</li>
+                <li className="user-page-email">
+                  <i className="icon-envelope mr-1"></i>
+                  {pageUser.isEmailPublished ? pageUser.email : '*****'}
+                </li>
+                {pageUser.introduction && <li className="user-page-introduction"><p>{pageUser.introduction}</p></li>}
+              </ul>
+            </div>
+          </div>
+        </div>
+
+        {/* Header Button */}
+        <BookmarkButton pageId={pageId} crowi={appContainer} />
+      </div>
+
+
+    </div>
+  );
+
+};
+
+/**
+ * Wrapper component for using unstated
+ */
+const GrowiSubNavigationForUserPageWrapper = (props) => {
+  return createSubscribedElement(GrowiSubNavigationForUserPage, props, [AppContainer, PageContainer]);
+};
+
+
+GrowiSubNavigationForUserPage.propTypes = {
+  t: PropTypes.func.isRequired, //  i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
+};
+
+export default withTranslation()(GrowiSubNavigationForUserPageWrapper);

+ 0 - 218
src/server/routes/bookmark.js

@@ -1,218 +0,0 @@
-/**
- * @swagger
- *  tags:
- *    name: Bookmarks
- */
-
-/**
- * @swagger
- *
- *  components:
- *    schemas:
- *      Bookmark:
- *        description: Bookmark
- *        type: object
- *        properties:
- *          _id:
- *            type: string
- *            description: page ID
- *            example: 5e07345972560e001761fa63
- *          __v:
- *            type: number
- *            description: DB record version
- *            example: 0
- *          createdAt:
- *            type: string
- *            description: date created at
- *            example: 2010-01-01T00:00:00.000Z
- *          page:
- *            $ref: '#/components/schemas/Page/properties/_id'
- *          user:
- *            $ref: '#/components/schemas/User/properties/_id'
- */
-
-module.exports = function(crowi, app) {
-  const debug = require('debug')('growi:routes:bookmark');
-  const Bookmark = crowi.model('Bookmark');
-  const Page = crowi.model('Page');
-  const ApiResponse = require('../util/apiResponse');
-  const ApiPaginate = require('../util/apiPaginate');
-  const actions = {};
-  actions.api = {};
-
-  /**
-   * @swagger
-   *
-   *    /bookmarks.get:
-   *      get:
-   *        tags: [Bookmarks, CrowiCompatibles]
-   *        operationId: getBookmark
-   *        summary: /bookmarks.get
-   *        description: Get bookmark of the page with the user
-   *        parameters:
-   *          - in: query
-   *            name: page_id
-   *            required: true
-   *            schema:
-   *              $ref: '#/components/schemas/Page/properties/_id'
-   *        responses:
-   *          200:
-   *            description: Succeeded to get bookmark of the page with the user.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    bookmark:
-   *                      $ref: '#/components/schemas/Bookmark'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {get} /bookmarks.get Get bookmark of the page with the user
-   * @apiName GetBookmarks
-   * @apiGroup Bookmark
-   *
-   * @apiParam {String} page_id Page Id.
-   */
-  actions.api.get = function(req, res) {
-    const pageId = req.query.page_id;
-
-    Bookmark.findByPageIdAndUserId(pageId, req.user)
-      .then((data) => {
-        debug('bookmark found', pageId, data);
-        const result = {};
-
-        result.bookmark = data;
-        return res.json(ApiResponse.success(result));
-      })
-      .catch((err) => {
-        return res.json(ApiResponse.error(err));
-      });
-  };
-
-  actions.api.list = function(req, res) {
-    const paginateOptions = ApiPaginate.parseOptions(req.query);
-
-    const options = Object.assign(paginateOptions, { populatePage: true });
-    Bookmark.findByUserId(req.user._id, options)
-      .then((result) => {
-        return res.json(ApiResponse.success(result));
-      })
-      .catch((err) => {
-        return res.json(ApiResponse.error(err));
-      });
-  };
-
-  /**
-   * @swagger
-   *
-   *    /bookmarks.add:
-   *      post:
-   *        tags: [Bookmarks, CrowiCompatibles]
-   *        operationId: addBookmark
-   *        summary: /bookmarks.add
-   *        description: Add bookmark of the page
-   *        parameters:
-   *          - in: query
-   *            name: page_id
-   *            schema:
-   *              $ref: '#/components/schemas/Page/properties/_id'
-   *            required: true
-   *        responses:
-   *          200:
-   *            description: Succeeded to add bookmark of the page.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    bookmark:
-   *                      $ref: '#/components/schemas/Bookmark'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {post} /bookmarks.add Add bookmark of the page
-   * @apiName AddBookmark
-   * @apiGroup Bookmark
-   *
-   * @apiParam {String} page_id Page Id.
-   */
-  actions.api.add = async function(req, res) {
-    const pageId = req.body.page_id;
-
-    const page = await Page.findByIdAndViewer(pageId, req.user);
-    if (page == null) {
-      return res.json(ApiResponse.success({ bookmark: null }));
-    }
-
-    const bookmark = await Bookmark.add(page, req.user);
-
-    bookmark.depopulate('page');
-    bookmark.depopulate('user');
-    const result = { bookmark };
-
-    return res.json(ApiResponse.success(result));
-  };
-
-  /**
-   * @swagger
-   *
-   *    /bookmarks.remove:
-   *      post:
-   *        tags: [Bookmarks, CrowiCompatibles]
-   *        operationId: removeBookmark
-   *        summary: /bookmarks.remove
-   *        description: Remove bookmark of the page
-   *        requestBody:
-   *          content:
-   *            application/json:
-   *              schema:
-   *                properties:
-   *                  page_id:
-   *                    $ref: '#/components/schemas/Page/properties/_id'
-   *                required:
-   *                  - page_id
-   *        responses:
-   *          200:
-   *            description: Succeeded to remove bookmark of the page.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {post} /bookmarks.remove Remove bookmark of the page
-   * @apiName RemoveBookmark
-   * @apiGroup Bookmark
-   *
-   * @apiParam {String} page_id Page Id.
-   */
-  actions.api.remove = function(req, res) {
-    const pageId = req.body.page_id;
-
-    Bookmark.removeBookmark(pageId, req.user)
-      .then((data) => {
-        debug('Bookmark removed.', data); // if the bookmark is not exists, this 'data' is null
-        return res.json(ApiResponse.success());
-      })
-      .catch((err) => {
-        return res.json(ApiResponse.error(err));
-      });
-  };
-
-  return actions;
-};

+ 0 - 6
src/server/routes/index.js

@@ -23,7 +23,6 @@ module.exports = function(crowi, app) {
   const user = require('./user')(crowi, app);
   const user = require('./user')(crowi, app);
   const attachment = require('./attachment')(crowi, app);
   const attachment = require('./attachment')(crowi, app);
   const comment = require('./comment')(crowi, app);
   const comment = require('./comment')(crowi, app);
-  const bookmark = require('./bookmark')(crowi, app);
   const tag = require('./tag')(crowi, app);
   const tag = require('./tag')(crowi, app);
   const revision = require('./revision')(crowi, app);
   const revision = require('./revision')(crowi, app);
   const search = require('./search')(crowi, app);
   const search = require('./search')(crowi, app);
@@ -160,11 +159,6 @@ module.exports = function(crowi, app) {
   app.post('/_api/comments.add'       , comment.api.validators.add(), accessTokenParser , loginRequiredStrictly , csrf, comment.api.add);
   app.post('/_api/comments.add'       , comment.api.validators.add(), accessTokenParser , loginRequiredStrictly , csrf, comment.api.add);
   app.post('/_api/comments.update'    , comment.api.validators.add(), accessTokenParser , loginRequiredStrictly , csrf, comment.api.update);
   app.post('/_api/comments.update'    , comment.api.validators.add(), accessTokenParser , loginRequiredStrictly , csrf, comment.api.update);
   app.post('/_api/comments.remove'    , accessTokenParser , loginRequiredStrictly , csrf, comment.api.remove);
   app.post('/_api/comments.remove'    , accessTokenParser , loginRequiredStrictly , csrf, comment.api.remove);
-  app.get('/_api/bookmarks.get'       , accessTokenParser , loginRequired , bookmark.api.get);
-  app.post('/_api/bookmarks.add'      , accessTokenParser , loginRequiredStrictly , csrf, bookmark.api.add);
-  app.post('/_api/bookmarks.remove'   , accessTokenParser , loginRequiredStrictly , csrf, bookmark.api.remove);
-  app.post('/_api/likes.add'          , accessTokenParser , loginRequiredStrictly , csrf, page.api.like);
-  app.post('/_api/likes.remove'       , accessTokenParser , loginRequiredStrictly , csrf, page.api.unlike);
   app.get('/_api/attachments.list'    , accessTokenParser , loginRequired , attachment.api.list);
   app.get('/_api/attachments.list'    , accessTokenParser , loginRequired , attachment.api.list);
   app.post('/_api/attachments.add'                  , uploads.single('file'), autoReap, accessTokenParser, loginRequiredStrictly ,csrf, attachment.api.add);
   app.post('/_api/attachments.add'                  , uploads.single('file'), autoReap, accessTokenParser, loginRequiredStrictly ,csrf, attachment.api.add);
   app.post('/_api/attachments.uploadProfileImage'   , uploads.single('file'), autoReap, accessTokenParser, loginRequiredStrictly ,csrf, attachment.api.uploadProfileImage);
   app.post('/_api/attachments.uploadProfileImage'   , uploads.single('file'), autoReap, accessTokenParser, loginRequiredStrictly ,csrf, attachment.api.uploadProfileImage);

+ 0 - 144
src/server/routes/page.js

@@ -1230,150 +1230,6 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success(result));
     return res.json(ApiResponse.success(result));
   };
   };
 
 
-  /**
-   * @swagger
-   *
-   *    /likes.add:
-   *      post:
-   *        tags: [Likes, CrowiCompatibles]
-   *        operationId: addLike
-   *        summary: /likes.add
-   *        description: Like page
-   *        requestBody:
-   *          content:
-   *            application/json:
-   *              schema:
-   *                properties:
-   *                  page_id:
-   *                    $ref: '#/components/schemas/Page/properties/_id'
-   *                required:
-   *                  - page_id
-   *        responses:
-   *          200:
-   *            description: Succeeded to be page liked.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    page:
-   *                      $ref: '#/components/schemas/Page'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {post} /likes.add Like page
-   * @apiName LikePage
-   * @apiGroup Page
-   *
-   * @apiParam {String} page_id Page Id.
-   */
-  api.like = async function(req, res) {
-    const pageId = req.body.page_id;
-    if (!pageId) {
-      return res.json(ApiResponse.error('page_id required'));
-    }
-    if (!req.user) {
-      return res.json(ApiResponse.error('user required'));
-    }
-
-    let page;
-    try {
-      page = await Page.findByIdAndViewer(pageId, req.user);
-      if (page == null) {
-        throw new Error(`Page '${pageId}' is not found or forbidden`);
-      }
-      page = await page.like(req.user);
-    }
-    catch (err) {
-      debug('Seen user update error', err);
-      return res.json(ApiResponse.error(err));
-    }
-
-    const result = { page };
-    result.seenUser = page.seenUsers;
-    res.json(ApiResponse.success(result));
-
-    try {
-      // global notification
-      await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_LIKE, page, req.user);
-    }
-    catch (err) {
-      logger.error('Like notification failed', err);
-    }
-  };
-
-  /**
-   * @swagger
-   *
-   *    /likes.remove:
-   *      post:
-   *        tags: [Likes, CrowiCompatibles]
-   *        operationId: removeLike
-   *        summary: /likes.remove
-   *        description: Unlike page
-   *        requestBody:
-   *          content:
-   *            application/json:
-   *              schema:
-   *                properties:
-   *                  page_id:
-   *                    $ref: '#/components/schemas/Page/properties/_id'
-   *                required:
-   *                  - page_id
-   *        responses:
-   *          200:
-   *            description: Succeeded to not be page liked.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    page:
-   *                      $ref: '#/components/schemas/Page'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {post} /likes.remove Unlike page
-   * @apiName UnlikePage
-   * @apiGroup Page
-   *
-   * @apiParam {String} page_id Page Id.
-   */
-  api.unlike = async function(req, res) {
-    const pageId = req.body.page_id;
-    if (!pageId) {
-      return res.json(ApiResponse.error('page_id required'));
-    }
-    if (req.user == null) {
-      return res.json(ApiResponse.error('user required'));
-    }
-
-    let page;
-    try {
-      page = await Page.findByIdAndViewer(pageId, req.user);
-      if (page == null) {
-        throw new Error(`Page '${pageId}' is not found or forbidden`);
-      }
-      page = await page.unlike(req.user);
-    }
-    catch (err) {
-      debug('Seen user update error', err);
-      return res.json(ApiResponse.error(err));
-    }
-
-    const result = { page };
-    result.seenUser = page.seenUsers;
-    return res.json(ApiResponse.success(result));
-  };
-
   /**
   /**
    * @swagger
    * @swagger
    *
    *

+ 1 - 1
src/server/views/layout-growi/user_page.html

@@ -7,7 +7,7 @@
 
 
 {% block content_header %}
 {% block content_header %}
   {% if pageUser %}
   {% if pageUser %}
-    {% include '../widget/user_page_header.html' %}
+    <header id="grw-subnav-for-user-page" class="user-page-header" data-page-user="{{ pageUser|json }}"></header>
   {% else %}
   {% else %}
     {% parent %}
     {% parent %}
   {% endif %}
   {% endif %}

+ 1 - 1
src/server/views/layout-kibela/user_page.html

@@ -7,7 +7,7 @@
 
 
 {% block content_header %}
 {% block content_header %}
   {% if pageUser %}
   {% if pageUser %}
-    {% include '../widget/user_page_header.html' %}
+    <header id="grw-subnav-for-user-page" class="user-page-header" data-page-user="{{ pageUser|json }}"></header>
   {% else %}
   {% else %}
     {% parent %}
     {% parent %}
   {% endif %}
   {% endif %}

+ 0 - 31
src/server/views/widget/user_page_header.html

@@ -1,31 +0,0 @@
-<header id="page-header" class="user-page-header">
-
-  <h4 id="revision-path"></h4>
-
-  <div class="users-info d-flex align-items-center">
-    <img src="{{ pageUser|picture }}" class="picture rounded-circle">
-    <div class="users-meta" style="flex: 1;">
-      <div class="d-flex align-items-center">
-        <h1>
-          {{ pageUser.name }}
-        </h1>
-      </div>
-      <div class="user-page-meta">
-        <ul>
-          <li class="user-page-username"><i class="icon-user"></i> {{ pageUser.username }}</li>
-          <li class="user-page-email">
-            <i class="icon-envelope"></i>
-            {% if pageUser.isEmailPublished %}
-              {{ pageUser.email }}
-            {% else %}
-              *****
-            {% endif %}
-          </li>
-          {% if pageUser.introduction %}
-          <li class="user-page-introduction"><p>{{ pageUser.introduction|nl2br }}</p></li>
-          {% endif %}
-        </ul>
-      </div>
-    </div>
-  </div>
-</header>