|
|
@@ -26,13 +26,16 @@ module.exports = function(crowi) {
|
|
|
}
|
|
|
|
|
|
pageSchema = new mongoose.Schema({
|
|
|
- path: { type: String, required: true, index: true },
|
|
|
+ path: { type: String, required: true, index: true, unique: true },
|
|
|
revision: { type: ObjectId, ref: 'Revision' },
|
|
|
redirectTo: { type: String, index: true },
|
|
|
status: { type: String, default: STATUS_PUBLISHED, index: true },
|
|
|
grant: { type: Number, default: GRANT_PUBLIC, index: true },
|
|
|
grantedUsers: [{ type: ObjectId, ref: 'User' }],
|
|
|
creator: { type: ObjectId, ref: 'User', index: true },
|
|
|
+ // lastUpdateUser: this schema is from 1.5.x (by deletion feature), and null is default.
|
|
|
+ // the last update user on the screen is by revesion.author for B.C.
|
|
|
+ lastUpdateUser: { type: ObjectId, ref: 'User', index: true },
|
|
|
liker: [{ type: ObjectId, ref: 'User', index: true }],
|
|
|
seenUsers: [{ type: ObjectId, ref: 'User', index: true }],
|
|
|
commentCount: { type: Number, default: 0 },
|
|
|
@@ -711,6 +714,7 @@ module.exports = function(crowi) {
|
|
|
|
|
|
debug('Successfully saved new revision', newRevision);
|
|
|
pageData.revision = newRevision;
|
|
|
+ pageData.lastUpdateUser = user;
|
|
|
pageData.updatedAt = Date.now();
|
|
|
pageData.save(function(err, data) {
|
|
|
if (err) {
|
|
|
@@ -749,6 +753,7 @@ module.exports = function(crowi) {
|
|
|
var newPage = new Page();
|
|
|
newPage.path = path;
|
|
|
newPage.creator = user;
|
|
|
+ newPage.lastUpdateUser = user;
|
|
|
newPage.createdAt = Date.now();
|
|
|
newPage.updatedAt = Date.now();
|
|
|
newPage.redirectTo = redirectTo;
|
|
|
@@ -809,9 +814,14 @@ module.exports = function(crowi) {
|
|
|
;
|
|
|
if (Page.isDeletableName(pageData.path)) {
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
- Page.updatePageProperty(pageData, {status: STATUS_DELETED})
|
|
|
+ Page.updatePageProperty(pageData, {status: STATUS_DELETED, lastUpdateUser: user})
|
|
|
.then(function(data) {
|
|
|
pageData.status = STATUS_DELETED;
|
|
|
+
|
|
|
+ // ページ名が /trash/ 以下に存在する場合、おかしなことになる
|
|
|
+ // が、 /trash 以下にページが有るのは、個別に作っていたケースのみ。
|
|
|
+ // 一応しばらく前から uncreatable pages になっているのでこれでいいことにする
|
|
|
+ debug('Deleted the page, and rename it', pageData.path, newPath);
|
|
|
return Page.rename(pageData, newPath, user, {createRedirectPage: true})
|
|
|
}).then(function(pageData) {
|
|
|
resolve(pageData);
|
|
|
@@ -823,6 +833,81 @@ module.exports = function(crowi) {
|
|
|
};
|
|
|
|
|
|
pageSchema.statics.revertDeletedPage = function(pageData, user, options) {
|
|
|
+ var Page = this
|
|
|
+ , newPath = Page.getRevertDeletedPageName(pageData.path)
|
|
|
+ ;
|
|
|
+
|
|
|
+ // 削除時、元ページの path には必ず redirectTo 付きで、ページが作成される。
|
|
|
+ // そのため、そいつは削除してOK
|
|
|
+ // が、redirectTo ではないページが存在している場合それは何かがおかしい。(データ補正が必要)
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
+ Page.findPageByPath(newPath)
|
|
|
+ .then(function(originPageData) {
|
|
|
+ if (originPageData.redirectTo !== pageData.path) {
|
|
|
+ throw new Error('The new page of to revert is exists and the redirect path of the page is not the deleted page.');
|
|
|
+ }
|
|
|
+
|
|
|
+ return Page.completelyDeletePage(originPageData);
|
|
|
+ }).then(function(done) {
|
|
|
+ return Page.updatePageProperty(pageData, {status: STATUS_PUBLISHED, lastUpdateUser: user})
|
|
|
+ }).then(function(done) {
|
|
|
+ pageData.status = STATUS_PUBLISHED;
|
|
|
+
|
|
|
+ debug('Revert deleted the page, and rename again it', pageData, newPath);
|
|
|
+ return Page.rename(pageData, newPath, user, {})
|
|
|
+ }).then(function(done) {
|
|
|
+ pageData.path = newPath;
|
|
|
+ resolve(pageData);
|
|
|
+ }).catch(reject);
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This is danger.
|
|
|
+ */
|
|
|
+ pageSchema.statics.completelyDeletePage = function(pageData, user, options) {
|
|
|
+ // Delete Bookmarks, Attachments, Revisions, Pages and emit delete
|
|
|
+ var Bookmark = crowi.model('Bookmark')
|
|
|
+ , Attachment = crowi.model('Attachment')
|
|
|
+ , Comment = crowi.model('Comment')
|
|
|
+ , Revision = crowi.model('Revision')
|
|
|
+ , Page = this
|
|
|
+ , pageId = pageData._id
|
|
|
+ ;
|
|
|
+
|
|
|
+ debug('Completely delete', pageData.path);
|
|
|
+
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
+ Bookmark.removeBookmarksByPageId(pageId)
|
|
|
+ .then(function(done) {
|
|
|
+ }).then(function(done) {
|
|
|
+ return Attachment.removeAttachmentsByPageId(pageId);
|
|
|
+ }).then(function(done) {
|
|
|
+ return Comment.removeCommentsByPageId(pageId);
|
|
|
+ }).then(function(done) {
|
|
|
+ return Revision.removeRevisionsByPath(pageData.path);
|
|
|
+ }).then(function(done) {
|
|
|
+ return Page.removePageById(pageId);
|
|
|
+ }).then(function(done) {
|
|
|
+ pageEvent.emit('delete', pageData, user); // update as renamed page
|
|
|
+ resolve();
|
|
|
+ }).catch(reject);
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ pageSchema.statics.removePageById = function(pageId) {
|
|
|
+ var Page = this;
|
|
|
+
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
+ Page.remove({_id: pageId}, function(err, done) {
|
|
|
+ debug('Remove phisiaclly, the page', pageId, err, done);
|
|
|
+ if (err) {
|
|
|
+ return reject(err);
|
|
|
+ }
|
|
|
+
|
|
|
+ resolve(done);
|
|
|
+ });
|
|
|
+ });
|
|
|
};
|
|
|
|
|
|
pageSchema.statics.rename = function(pageData, newPagePath, user, options) {
|
|
|
@@ -834,13 +919,11 @@ module.exports = function(crowi) {
|
|
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
// pageData の path を変更
|
|
|
- Page.updatePageProperty(pageData, {updatedAt: Date.now(), path: newPagePath})
|
|
|
+ Page.updatePageProperty(pageData, {updatedAt: Date.now(), path: newPagePath, lastUpdateUser: user})
|
|
|
.then(function(data) {
|
|
|
- debug('Before ', pageData);
|
|
|
// reivisions の path を変更
|
|
|
return Revision.updateRevisionListByPath(path, {path: newPagePath}, {})
|
|
|
}).then(function(data) {
|
|
|
- debug('After ', pageData);
|
|
|
pageData.path = newPagePath;
|
|
|
|
|
|
if (createRedirectPage) {
|