Преглед изворни кода

Merge pull request #611 from weseek/feat/gc-939-gc992_recentCreated_serverReqRes

gc939-gc992_recentCreated_serverReqRes
Yuki Takei пре 7 година
родитељ
комит
51341e1b98

+ 1 - 1
src/client/js/app.js

@@ -332,7 +332,7 @@ if (savePageControlsElem) {
 const recentCreatedControlsElem = document.getElementById('user-created-list');
 if (recentCreatedControlsElem) {
   ReactDOM.render(
-    <RecentCreated >
+    <RecentCreated  crowi={crowi} pageId={pageId}  >
 
     </RecentCreated>, document.getElementById('user-created-list')
   );

+ 176 - 85
src/client/js/components/RecentCreated/RecentCreated.js

@@ -1,107 +1,198 @@
 import React from 'react';
+import UserPicture from '../User/UserPicture';
+
 import PropTypes from 'prop-types';
-//import { Pagination }  from 'react-js-pagination';
 import Pagination from 'react-bootstrap/lib/Pagination';
 export default class RecentCreated extends React.Component {
 
-  render() {
-    const testval = null;
-    let active = 7;
-    let items = [];
-    for (let number = 1; number <= 10; number++) {
-      items.push(
-        <Pagination.Item active={number === active}>{number}</Pagination.Item>
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      pages: [],
+      limit: 10, // TODO GC-941で対応予定
+      activePage: 1,
+      PaginationNumbers: {},
+
+    };
+    this.calculatePagination = this.calculatePagination.bind(this);
+  }
+
+
+  componentWillMount() {
+    this.getRecentCreatedList(1);
+  }
+  getRecentCreatedList(selectPageNumber) {
+
+    const pageId = this.props.pageId;
+    const userId = this.props.crowi.me;
+    const limit = this.state.limit;
+    const offset = (selectPageNumber - 1) * limit;
+
+    // pagesList get and pagination calculate
+    this.props.crowi.apiGet('/pages.recentCreated', {page_id: pageId, user: userId, limit: limit, offset: offset, })
+      .then(res => {
+        const totalCount = res.pages[0].totalCount;
+        const activePage = selectPageNumber;
+        const pages = res.pages[1];
+        // pagiNation calculate function call
+        const PaginationNumbers = this.calculatePagination(limit, totalCount, activePage);
+        this.setState({
+          pages,
+          activePage,
+          PaginationNumbers,
+        });
+      });
+  }
+  calculatePagination(limit, totalCount, activePage) {
+    let PaginationNumbers = {};
+    // pagiNation totalPageNumber calculate
+    let totalPage = Math.floor(totalCount / limit) + (totalCount % limit === 0 ? 0  : 1);
+    let paginationStart = activePage - 2;
+    let maxViewPageNum =  activePage + 2;
+    // pagiNation Number area size = 5 , pageNuber calculate in here
+    // activePage Position calculate ex. 4 5 [6] 7 8 (Page8 over is Max), 3 4 5 [6] 7 (Page7 is Max)
+    if ( paginationStart < 1 ) {
+      const diff = 1 - paginationStart;
+      paginationStart += diff;
+      maxViewPageNum = Math.min(totalPage, maxViewPageNum + diff);
+    }
+    if ( maxViewPageNum > totalPage ) {
+      const diff = maxViewPageNum - totalPage;
+      maxViewPageNum -= diff;
+      paginationStart = Math.max(1, paginationStart - diff);
+    }
+    PaginationNumbers.totalPage = totalPage;
+    PaginationNumbers.paginationStart = paginationStart;
+    PaginationNumbers.maxViewPageNum = maxViewPageNum;
+
+    return PaginationNumbers;
+  }
+  /**
+   * generate Elements of Page
+   *
+   * @param {any} pages Array of pages Model Obj
+   *
+   */
+  generatePageList(pages, user) {
+    return pages.map((page, i) => {
+      return (
+        <li key={i}>
+          <UserPicture user={user} />
+          <a href={page.path} className="page-list-link" data-path={page.path} data-short-path={page.revision.body}>{decodeURI(page.path)}</a>
+        </li>
+      );
+    });
+
+  }
+
+  /**
+   * generate Elements of Pagination First Prev
+   * ex.  <<   <   1  2  3  >  >>
+   * this function set << & <
+   */
+  generateFirstPrev(activePage) {
+    let paginationItems = [];
+    if (1 != activePage) {
+      paginationItems.push(
+        <Pagination.First key="first" onClick={() => this.getRecentCreatedList(1)} />
+      );
+      paginationItems.push(
+        <Pagination.Prev key="prev" onClick={() => this.getRecentCreatedList(this.state.activePage - 1)} />
       );
     }
+    else {
+      paginationItems.push(
+        <Pagination.First key="first" disabled />
+      );
+      paginationItems.push(
+        <Pagination.Prev key="prev" disabled />
+      );
+
+    }
+    return paginationItems;
+  }
+
+  /**
+   * generate Elements of Pagination First Prev
+   *  ex. << < 4 5 6 7 8 > >>, << < 1 2 3 4 > >>
+   * this function set  numbers
+   */
+  generatePaginations(activePage, paginationStart, maxViewPageNum) {
+    let paginationItems = [];
+    for (let number = paginationStart; number <= maxViewPageNum; number++) {
+      paginationItems.push(
+        <Pagination.Item key={number} active={number === activePage} onClick={ () => this.getRecentCreatedList(number)}>{number}</Pagination.Item>
+      );
+    }
+    return paginationItems;
+  }
+
+  /**
+   * generate Elements of Pagination First Prev
+   * ex.  <<   <   1  2  3  >  >>
+   * this function set > & >>
+   */
+  generateNextLast(activePage, totalPage) {
+    let paginationItems = [];
+    if (totalPage != activePage) {
+      paginationItems.push(
+        <Pagination.Next key="next" onClick={() => this.getRecentCreatedList(this.state.activePage + 1)} />
+      );
+      paginationItems.push(
+        <Pagination.Last key="last" onClick={() => this.getRecentCreatedList(totalPage)} />
+      );
+    }
+    else {
+      paginationItems.push(
+        <Pagination.Next key="next" disabled />
+      );
+      paginationItems.push(
+        <Pagination.Last key="last" disabled />
+      );
+
+    }
+    return paginationItems;
+
+  }
+
+  render() {
+    const username = this.props.crowi.me;
+    const user = this.props.crowi.findUser(username);
+    const pageList = this.generatePageList(this.state.pages, user);
+
+    let paginationItems = [];
+    let activePage = this.state.activePage;
+    let totalPage = this.state.PaginationNumbers.totalPage;
+    let paginationStart = this.state.PaginationNumbers.paginationStart;
+    let maxViewPageNum =  this.state.PaginationNumbers.maxViewPageNum;
+    let firstPrevItems = this.generateFirstPrev(activePage);
+    paginationItems.push(firstPrevItems);
+    let paginations = this.generatePaginations(activePage, paginationStart, maxViewPageNum);
+    paginationItems.push(paginations);
+    let nextLastItems = this.generateNextLast(activePage, totalPage);
+    paginationItems.push(nextLastItems);
+
     return (
       <div className="page-list-container-create">
         <ul className="page-list-ul page-list-ul-flat">
-          <li>
-            <img src="/images/icons/user.svg" className="picture img-circle" ></img>
-            <a href="/Sandbox/Bootstrap3" className="page-list-link" data-path="/Sandbox/Bootstrap3" data-short-path="Bootstrap3">/reactTest1
-            </a>
-            <span className="page-list-meta">
-            </span>
-          </li>
-          <li>
-            <img src="/images/icons/user.svg" className="picture img-circle" ></img>
-            <a href="/Sandbox/Bootstrap3" className="page-list-link" data-path="/Sandbox/Bootstrap3" data-short-path="Bootstrap3">/reactTest2
-            </a>
-            <span className="page-list-meta">
-            </span>
-          </li>
-          <li>
-            <img src="/images/icons/user.svg" className="picture img-circle" ></img>
-            <a href="/Sandbox/Bootstrap3" className="page-list-link" data-path="/Sandbox/Bootstrap3" data-short-path="Bootstrap3">/reactTest3
-            </a>
-            <span className="page-list-meta">
-            </span>
-          </li>
-          <li>
-            <img src="/images/icons/user.svg" className="picture img-circle" ></img>
-            <a href="/Sandbox/Bootstrap3" className="page-list-link" data-path="/Sandbox/Bootstrap3" data-short-path="Bootstrap3">/reactTest4
-            </a>
-            <span className="page-list-meta">
-            </span>
-          </li>
-          <li>
-            <img src="/images/icons/user.svg" className="picture img-circle" ></img>
-            <a href="/Sandbox/Bootstrap3" className="page-list-link" data-path="/Sandbox/Bootstrap3" data-short-path="Bootstrap3">/reactTest5
-            </a>
-            <span className="page-list-meta">
-            </span>
-          </li>
-          <li>
-            <img src="/images/icons/user.svg" className="picture img-circle" ></img>
-            <a href="/Sandbox/Bootstrap3" className="page-list-link" data-path="/Sandbox/Bootstrap3" data-short-path="Bootstrap3">/reactTest6
-            </a>
-            <span className="page-list-meta">
-            </span>
-          </li>
-
-          <li>
-            <img src="/images/icons/user.svg" className="picture img-circle" ></img>
-            <a href="/Sandbox/Bootstrap3" className="page-list-link" data-path="/Sandbox/Bootstrap3" data-short-path="Bootstrap3">/reactTest7
-            </a>
-            <span className="page-list-meta">
-            </span>
-          </li>
-          <li>
-            <img src="/images/icons/user.svg" className="picture img-circle" ></img>
-            <a href="/" className="page-list-link" data-path="/" data-short-path="">/
-            </a>
-            <span className="page-list-meta">
-              <span className="label label-info">RE</span>
-            </span>
-          </li>
-          <li>
-            <img src="/images/icons/user.svg" className="picture img-circle" ></img>
-
-            <a href="/user/tsuyoshi" className="page-list-link" data-path="/user/tsuyoshi" data-short-path="tsuyoshi">/user/tsuyoshi/GC-939
-            </a>
-            <span className="page-list-meta">
-            </span>
-          </li>
-          <li>
-            <img src="/images/icons/user.svg" className="picture img-circle" ></img>
-            <a href="/Sandbox" className="page-list-link" data-path="/Sandbox" data-short-path="/Sandbox">/ReactComponentTest
-            </a>
-            <span className="page-list-meta">
-            </span>
-          </li>
+            {pageList}
         </ul>
-        <Pagination bsSize="small">{items}</Pagination>
+        {
+        <Pagination bsSize="small">{paginationItems}</Pagination>
+        }
       </div>
     );
   }
 }
 
+
+
 RecentCreated.propTypes = {
+  pageId: PropTypes.string.isRequired,
+  crowi: PropTypes.object.isRequired,
 };
 
 RecentCreated.defaultProps = {
-  page: {},
-  linkTo: '',
-  excludePathString: '',
 };
 

+ 35 - 25
src/server/models/page.js

@@ -669,38 +669,48 @@ module.exports = function(crowi) {
     });
   };
 
-  pageSchema.statics.findListByCreator = function(user, option, currentUser) {
-    var Page = this;
-    var User = crowi.model('User');
-    var limit = option.limit || 50;
-    var offset = option.offset || 0;
-    var conditions = {
+  pageSchema.statics.findListByCreator = async function(user, option, currentUser) {
+    let Page = this;
+    let User = crowi.model('User');
+    let limit = option.limit || 50;
+    let offset = option.offset || 0;
+    let conditions = setPageListConditions(user);
+
+    let pages =  await Page.find(conditions).sort({createdAt: -1}).skip(offset).limit(limit).populate('revision').exec();
+    let PagesList = await Page.populate(pages, {path: 'lastUpdateUser', model: 'User', select: User.USER_PUBLIC_FIELDS});
+    let totalCount = await Page.countListByCreator(user);
+    let PagesArray = [
+      {totalCount: totalCount}
+    ];
+    PagesArray.push(PagesList);
+    return PagesArray;
+  };
+  function setPageListConditions(user) {
+    const conditions = {
       creator: user._id,
       redirectTo: null,
-      $or: [
-        {status: null},
-        {status: STATUS_PUBLISHED},
-      ],
+      $and: [
+        {$or: [
+          {status: null},
+          {status: STATUS_PUBLISHED},
+        ]},
+        {$or: [
+          {grant: GRANT_PUBLIC},
+          {grant: GRANT_USER_GROUP},
+        ]}],
     };
 
-    if (!user.equals(currentUser._id)) {
-      conditions.grant = GRANT_PUBLIC;
-    }
+    return conditions;
+  }
 
-    return new Promise(function(resolve, reject) {
-      Page
-      .find(conditions)
-      .sort({createdAt: -1})
-      .skip(offset)
-      .limit(limit)
-      .populate('revision')
-      .exec()
-      .then(function(pages) {
-        return Page.populate(pages, {path: 'lastUpdateUser', model: 'User', select: User.USER_PUBLIC_FIELDS}).then(resolve);
-      });
-    });
+  pageSchema.statics.countListByCreator = function(user) {
+    let Page = this;
+    let conditions = setPageListConditions(user);
+
+    return Page.find(conditions).count();
   };
 
+
   /**
    * Bulk get (for internal only)
    */

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

@@ -188,6 +188,7 @@ module.exports = function(crowi, app) {
   // HTTP RPC Styled API (に徐々に移行していいこうと思う)
   app.get('/_api/users.list'          , accessTokenParser , loginRequired(crowi, app, false) , user.api.list);
   app.get('/_api/pages.list'          , accessTokenParser , loginRequired(crowi, app, false) , page.api.list);
+  app.get('/_api/pages.recentCreated' , accessTokenParser , loginRequired(crowi, app, false) , page.api.recentCreated);
   app.post('/_api/pages.create'       , accessTokenParser , loginRequired(crowi, app) , csrf, page.api.create);
   app.post('/_api/pages.update'       , accessTokenParser , loginRequired(crowi, app) , csrf, page.api.update);
   app.get('/_api/pages.get'           , accessTokenParser , loginRequired(crowi, app, false) , page.api.get);

+ 29 - 1
src/server/routes/page.js

@@ -734,7 +734,7 @@ module.exports = function(crowi, app) {
   api.list = function(req, res) {
     const username = req.query.user || null;
     const path = req.query.path || null;
-    const limit = 50;
+    const limit = + req.query.limit || 50;
     const offset = parseInt(req.query.offset) || 0;
 
     const pagerOptions = { offset: offset, limit: limit };
@@ -1262,5 +1262,33 @@ module.exports = function(crowi, app) {
     });
   };
 
+  api.recentCreated = async function(req, res) {
+    const username = req.query.user || null;
+    const limit = + req.query.limit || 50;
+    const offset = + req.query.offset || 0;
+
+    const queryOptions = { offset: offset, limit: limit };
+
+    if (username == null ) {
+      return res.json(ApiResponse.error('Parameter user is required.'));
+    }
+
+    try {
+      let user = await User.findUserByUsername(username);
+      if (user == null) {
+        throw new Error('The user not found.');
+      }
+      let pages = await Page.findListByCreator(user, queryOptions, req.user);
+
+      const result = {};
+      result.pages = pagePathUtils.encodePagesPath(pages);
+
+      return res.json(ApiResponse.success(result));
+    }
+    catch (err) {
+      return res.json(ApiResponse.error(err));
+    }
+  };
+
   return actions;
 };