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

Merge branch 'support/mirror-mode' into support/fix-i18n

ryuichi-e 6 лет назад
Родитель
Сommit
50f98c72b2

+ 18 - 1
CHANGES.md

@@ -1,9 +1,26 @@
 # CHANGES
 
-## v3.7.3-RC
+## v3.7.5
 
 *
 
+## v3.7.4
+
+* Fix: Broken by displaying user image
+
+## v3.7.3
+
+* Feature: Profile Image Cropping
+* Improvement: Reactify users pages
+* Improvement: Detect language and adjust the order of first and last names when creating accounts in OAuth
+* Fix: Installation is broken when selecting Japanese
+    * Introduced by 3.7.0
+* Fix: Mathjax Rendering is unstable (workaround)
+    * Introduced by 3.7.0
+* Fix: Notification Setting couldn't update without slack token
+    * Introduced by 3.6.6
+* Support: Add GROWI Contributers
+
 ## v3.7.2
 
 * Feature: User Management Filtering/Sort

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "3.7.3-RC",
+  "version": "3.7.4-RC",
   "description": "Team collaboration software using markdown",
   "tags": [
     "wiki",

+ 135 - 0
resource/locales/ja/sandbox-bootstrap3.md

@@ -0,0 +1,135 @@
+# Labels
+
+<span class="label label-default">Default</span>
+<span class="label label-primary">Primary</span>
+<span class="label label-success">Success</span>
+<span class="label label-info">Info</span>
+<span class="label label-warning">Warning</span>
+<span class="label label-danger">Danger</span>
+
+# Alerts
+
+<div class="alert alert-success" role="alert"><b>Well done!</b> You successfully read this important alert message. </div>
+<div class="alert alert-info" role="alert"><b>Heads up!</b> This alert needs your attention, but it's not super important. </div>
+<div class="alert alert-warning" role="alert"><b>Warning!</b> Better check yourself, you're not looking too good. </div>
+<div class="alert alert-danger" role="alert"><b>Oh snap!</b> Change a few things up and try submitting again. </div>
+
+# Panels
+
+<div class="panel panel-default">
+  <div class="panel-heading">Panel heading without title</div>
+  <div class="panel-body">
+    Panel content
+  </div>
+</div>
+
+<div class="panel panel-primary">
+  <div class="panel-heading">Panel heading without title</div>
+  <div class="panel-body">
+    Panel content
+  </div>
+</div>
+
+<div class="panel panel-success">
+  <div class="panel-heading">Panel heading without title</div>
+  <div class="panel-body">
+    Panel content
+  </div>
+</div>
+
+<div class="panel panel-info">
+  <div class="panel-heading">Panel heading without title</div>
+  <div class="panel-body">
+    Panel content
+  </div>
+</div>
+
+<div class="panel panel-warning">
+  <div class="panel-heading">Panel heading without title</div>
+  <div class="panel-body">
+    Panel content
+  </div>
+</div>
+
+<div class="panel panel-danger">
+  <div class="panel-heading">Panel heading without title</div>
+  <div class="panel-body">
+    Panel content
+  </div>
+</div>
+
+# Wells
+
+## Default well
+
+<div class="well">Look, I'm in a well! </div>
+
+## Optional classes
+
+<div class="well well-lg">Look, I'm in a well! </div>
+
+<div class="well well-sm">Look, I'm in a well! </div>
+
+# Typography
+
+## Lead body copy
+
+<p class="lead">Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus.</p>
+
+## Marked text
+
+You can use the mark tag to <mark>highlight</mark> text.
+
+## Small text
+
+<small>This line of text is meant to be treated as fine print.</small>
+
+## Alignment classes
+
+<div class="panel panel-default">
+  <div class="panel-body">
+    <p class="text-left">Left aligned text.</p>
+    <p class="text-center">Center aligned text.</p>
+    <p class="text-right">Right aligned text.</p>
+    <p class="text-justify">Justified text.</p>
+    <p class="text-nowrap">No wrap text.</p>
+  </div>
+</div>
+
+## Transformation classes
+
+<div class="panel panel-default">
+  <div class="panel-body">
+    <p class="text-lowercase">Lowercased text.</p>
+    <p class="text-uppercase">Uppercased text.</p>
+    <p class="text-capitalize">Capitalized text.</p>
+  </div>
+</div>
+
+
+# Helper classes
+
+## Contextual colors
+
+<div class="panel panel-default">
+  <div class="panel-body">
+    <p class="text-muted">Fusce dapibus, tellus ac cursus commodo, tortor mauris nibh.</p>
+    <p class="text-primary">Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
+    <p class="text-success">Duis mollis, est non commodo luctus, nisi erat porttitor ligula.</p>
+    <p class="text-info">Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
+    <p class="text-warning">Etiam porta sem malesuada magna mollis euismod.</p>
+    <p class="text-danger">Donec ullamcorper nulla non metus auctor fringilla.</p>
+  </div>
+</div>
+
+## Contextual backgrounds
+
+<div class="panel panel-default">
+  <div class="panel-body">
+    <p class="bg-primary">Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
+    <p class="bg-success">Duis mollis, est non commodo luctus, nisi erat porttitor ligula.</p>
+    <p class="bg-info">Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
+    <p class="bg-warning">Etiam porta sem malesuada magna mollis euismod.</p>
+    <p class="bg-danger">Donec ullamcorper nulla non metus auctor fringilla.</p>
+  </div>
+</div>

+ 1 - 1
src/client/js/components/Admin/App/MailSetting.jsx

@@ -79,7 +79,7 @@ class MailSetting extends React.Component {
             <input
               className="form-control"
               type="text"
-              defaultValue={adminAppContainer.state.SmtpUser || ''}
+              defaultValue={adminAppContainer.state.smtpUser || ''}
               onChange={(e) => { adminAppContainer.changeSmtpUser(e.target.value) }}
             />
           </div>

+ 4 - 4
src/client/js/components/Admin/ExportArchiveData/SelectCollectionsModal.jsx

@@ -189,26 +189,26 @@ class SelectCollectionsModal extends React.Component {
             </div>
             <div className="row mt-4">
               <div className="col-xs-12">
-                <legend>Page Collections</legend>
+                <legend>MongoDB Page Collections</legend>
                 {this.renderGroups(GROUPS_PAGE)}
               </div>
             </div>
             <div className="row mt-4">
               <div className="col-xs-12">
-                <legend>User Collections</legend>
+                <legend>MongoDB User Collections</legend>
                 {this.renderGroups(GROUPS_USER, 'danger')}
                 {this.renderWarnForUser()}
               </div>
             </div>
             <div className="row mt-4">
               <div className="col-xs-12">
-                <legend>Config Collections</legend>
+                <legend>MongoDB Config Collections</legend>
                 {this.renderGroups(GROUPS_CONFIG)}
               </div>
             </div>
             <div className="row mt-4">
               <div className="col-xs-12">
-                <legend>Other Collections</legend>
+                <legend>MongoDB Other Collections</legend>
                 {this.renderOthers()}
               </div>
             </div>

+ 13 - 1
src/client/js/components/Page/RevisionBody.jsx

@@ -35,7 +35,19 @@ export default class RevisionBody extends React.PureComponent {
 
   renderMathJax() {
     const MathJax = window.MathJax;
-    MathJax.Hub.Queue(['Typeset', MathJax.Hub, this.element]);
+    // Workaround MathJax Rendering (Errors still occur, but MathJax can be rendered)
+    //
+    // Reason:
+    //   Addition of draw.io Integration causes initialization conflict between MathJax of draw.io and MathJax of GROWI.
+    //   So, before MathJax is initialized, execute renderMathJaxWithDebounce again.
+    //   Avoiding initialization of MathJax of draw.io solves the problem.
+    //   refs: https://github.com/jgraph/drawio/pull/831
+    if (MathJax != null && MathJax.Hub != null) {
+      MathJax.Hub.Queue(['Typeset', MathJax.Hub, this.element]);
+    }
+    else {
+      this.renderMathJaxWithDebounce();
+    }
   }
 
   generateInnerHtml(html) {

+ 9 - 1
src/client/js/components/StaffCredit/Contributor.js

@@ -9,6 +9,7 @@ const contributors = [
           { position: 'Founder', name: 'yuki-takei' },
           { position: 'Soncho 1st', name: 'mizozobu' },
           { position: 'Soncho 2nd', name: 'yusuketk' },
+          { position: 'Paladin', name: 'itizawa' },
         ],
       },
       {
@@ -19,7 +20,6 @@ const contributors = [
           { name: 'TatsuyaIse' },
           { name: 'shinoka7' },
           { name: 'SeiyaTashiro' },
-          { name: 'itizawa' },
           { name: 'TsuyoshiSuzukief' },
           { name: 'Yuchan4342' },
           { name: 'ryu-sato' },
@@ -28,6 +28,14 @@ const contributors = [
           { name: 'kaishuu0123' },
           { name: 'kouki-o' },
           { name: 'Angola' },
+          { name: 'Yohei-Shiina' },
+          { name: 'shukmos' },
+          { name: 'sooouh' },
+          { name: 'ryouhek' },
+          { name: 'ryuichi-e' },
+          { name: 'N1koge' },
+          { name: 'Ertai87' },
+          { name: 'kaoritokashiki' },
         ],
       },
     ],

+ 1 - 0
src/client/js/services/AdminGeneralSecurityContainer.js

@@ -39,6 +39,7 @@ export default class AdminGeneralSecurityContainer extends Container {
     const response = await this.appContainer.apiv3.get('/security-setting/');
     const { generalSetting, generalAuth } = response.data.securityParams;
     this.setState({
+      currentRestrictGuestMode: generalSetting.restrictGuestMode,
       currentPageCompleteDeletionAuthority: generalSetting.pageCompleteDeletionAuthority,
       isShowRestrictedByOwner: !generalSetting.hideRestrictedByOwner,
       isShowRestrictedByGroup: !generalSetting.hideRestrictedByGroup,

+ 3 - 0
src/client/js/services/PersonalContainer.js

@@ -70,6 +70,9 @@ export default class PersonalContainer extends Container {
    * define a function for uploaded picture
    */
   getUploadedPictureSrc(user) {
+    if (user == null) {
+      return DEFAULT_IMAGE;
+    }
     if (user.image) {
       this.setState({ isUploadedPicture: true });
       return user.image;

+ 30 - 0
src/migrations/2020040216038-remove-deleteduser-from-relationgroup.js

@@ -0,0 +1,30 @@
+require('module-alias/register');
+const logger = require('@alias/logger')('growi:migrate:remove-deleteduser-from-relationgroup');
+
+const mongoose = require('mongoose');
+const config = require('@root/config/migrate');
+
+const { getModelSafely } = require('@commons/util/mongoose-utils');
+
+module.exports = {
+  async up(db) {
+    logger.info('Apply migration');
+    mongoose.connect(config.mongoUri, config.mongodb.options);
+
+    const User = getModelSafely('User') || require('@server/models/user')();
+    const UserGroupRelation = getModelSafely('UserGroupRelation') || require('@server/models/user-group-relation')();
+
+    const deletedUsers = await User.find({ status: 4 }); // deleted user
+    const requests = await UserGroupRelation.remove({ relatedUser: deletedUsers });
+
+    if (requests.size === 0) {
+      return logger.info('This migration terminates without any changes.');
+    }
+    logger.info('Migration has successfully applied');
+
+  },
+
+  down(db) {
+    // do not rollback
+  },
+};

+ 6 - 4
src/server/models/bookmark.js

@@ -45,10 +45,12 @@ module.exports = function(crowi) {
     const Bookmark = this;
     const User = crowi.model('User');
 
-    return Bookmark.populate(bookmarks, [
-      { path: 'page' },
-      { path: 'lastUpdateUser', model: 'User', select: User.USER_PUBLIC_FIELDS },
-    ]);
+    return Bookmark.populate(bookmarks, {
+      path: 'page',
+      populate: {
+        path: 'lastUpdateUser', model: 'User', select: User.USER_PUBLIC_FIELDS, populate: User.IMAGE_POPULATION,
+      },
+    });
   };
 
   // bookmark チェック用

+ 2 - 2
src/server/routes/apiv3/notification-setting.js

@@ -14,9 +14,9 @@ const removeNullPropertyFromObject = require('../../../lib/util/removeNullProper
 
 const validator = {
   slackConfiguration: [
-    body('webhookUrl').isString().trim(),
+    body('webhookUrl').if(value => value != null).isString().trim(),
     body('isIncomingWebhookPrioritized').isBoolean(),
-    body('slackToken').isString().trim(),
+    body('slackToken').if(value => value != null).isString().trim(),
   ],
   userNotification: [
     body('pathPattern').isString().trim(),

+ 1 - 0
src/server/routes/apiv3/user-group.js

@@ -587,6 +587,7 @@ module.exports = (crowi) => {
         populate: {
           path: 'lastUpdateUser',
           select: User.USER_PUBLIC_FIELDS,
+          populate: User.IMAGE_POPULATION,
         },
       });
 

+ 1 - 0
src/server/routes/apiv3/users.js

@@ -182,6 +182,7 @@ module.exports = (crowi) => {
         },
         {
           sort: sortOutput,
+          populate: User.IMAGE_POPULATION,
           page,
           limit: PAGE_ITEMS,
         },

+ 7 - 2
src/server/routes/installer.js

@@ -21,8 +21,13 @@ module.exports = function(crowi, app) {
   }
 
   async function createPage(filePath, pagePath, owner, lang) {
-    const markdown = fs.readFileSync(filePath);
-    return Page.create(pagePath, markdown, owner, {});
+    try {
+      const markdown = fs.readFileSync(filePath);
+      return Page.create(pagePath, markdown, owner, {});
+    }
+    catch (err) {
+      logger.error(`Failed to create ${pagePath}`, err);
+    }
   }
 
   async function createInitialPages(owner, lang) {

+ 3 - 3
src/server/views/layout-growi/widget/header.html

@@ -31,7 +31,7 @@
               <img src="{{ page.creator|default(author)|picture }}" class="picture picture-xs img-circle">
             </a>
             <div class="ml-auto">
-              <div>Created in <span class="text-muted">{{ page.createdAt|datetz('Y/m/d H:i:s') }}</span></div>
+              <div>Created at <span class="text-muted">{{ page.createdAt|datetz('Y/m/d H:i:s') }}</span></div>
             </div>
           </div>
         </li>
@@ -42,7 +42,7 @@
             </a>
             <div>
               <div>Updated by <a href="{{ userPageRoot(page.revision.author) }}">{{ author.name }}</a></div>
-              <div class="text-muted"">{{ page.updatedAt|datetz('Y/m/d H:i:s') }}</div>
+              <div class="text-muted">{{ page.updatedAt|datetz('Y/m/d H:i:s') }}</div>
             </div>
           </div>
           <div class="d-flex align-items-center only-affix">
@@ -50,7 +50,7 @@
               <img src="{{ author|picture }}" class="picture picture-xs img-circle">
             </a>
             <div class="ml-auto">
-              <div>Updated in <span class="text-muted"">{{ page.updatedAt|datetz('Y/m/d H:i:s') }}</span></div>
+              <div>Updated at <span class="text-muted">{{ page.updatedAt|datetz('Y/m/d H:i:s') }}</span></div>
             </div>
           </div>
         </li>