Skip to content
This repository was archived by the owner on Feb 5, 2024. It is now read-only.

Commit 9fd88ba

Browse files
committed
tmp
1 parent 1c2217e commit 9fd88ba

File tree

8 files changed

+195
-53
lines changed

8 files changed

+195
-53
lines changed

lib/models/page.js

+71-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ module.exports = function(crowi) {
88
, GRANT_OWNER = 4
99
, PAGE_GRANT_ERROR = 1
1010

11+
, STATUS_WIP = 'wip'
12+
, STATUS_PUBLISHED = 'published'
13+
, STATUS_DELEDED = 'deleted'
14+
, STATUS_DEPRECATED = 'deprecated'
15+
1116
, pageEvent = crowi.event('page')
1217

1318
, pageSchema;
@@ -24,6 +29,7 @@ module.exports = function(crowi) {
2429
path: { type: String, required: true, index: true },
2530
revision: { type: ObjectId, ref: 'Revision' },
2631
redirectTo: { type: String, index: true },
32+
status: { type: String, default: STATUS_PUBLISHED, index: true },
2733
grant: { type: Number, default: GRANT_PUBLIC, index: true },
2834
grantedUsers: [{ type: ObjectId, ref: 'User' }],
2935
creator: { type: ObjectId, ref: 'User', index: true },
@@ -54,6 +60,23 @@ module.exports = function(crowi) {
5460
pageEvent.on('create', pageEvent.onCreate);
5561
pageEvent.on('update', pageEvent.onUpdate);
5662

63+
pageSchema.methods.isWIP = function() {
64+
return this.status === STATUS_WIP;
65+
};
66+
67+
pageSchema.methods.isPublished = function() {
68+
// null: this is for B.C.
69+
return this.status === null || this.status === STATUS_PUBLISHED;
70+
};
71+
72+
pageSchema.methods.isDeleted = function() {
73+
return this.status === STATUS_DELEDED;
74+
};
75+
76+
pageSchema.methods.isDeprecated = function() {
77+
return this.status === STATUS_DEPRECATED;
78+
};
79+
5780
pageSchema.methods.isPublic = function() {
5881
if (!this.grant || this.grant == GRANT_PUBLIC) {
5982
return true;
@@ -322,6 +345,32 @@ module.exports = function(crowi) {
322345
return '/user/' + user.username;
323346
};
324347

348+
pageSchema.statics.getDeletedPageName = function(path) {
349+
if (path.match('\/')) {
350+
path = path.substr(1);
351+
}
352+
return '/trash/' + path;
353+
};
354+
355+
pageSchema.statics.getRevertDeletedPageName = function(path) {
356+
return path.replace('\/trash', '');
357+
};
358+
359+
pageSchema.statics.isDeletableName = function(path) {
360+
var notDeletable = [
361+
/^\/user\/[^\/]+$/, // user page
362+
];
363+
364+
for (var i = 0; i < notDeletable.length; i++) {
365+
var pattern = notDeletable[i];
366+
if (path.match(pattern)) {
367+
return false;
368+
}
369+
}
370+
371+
return true;
372+
};
373+
325374
pageSchema.statics.isCreatableName = function(name) {
326375
var forbiddenPages = [
327376
/\^|\$|\*|\+|\#/,
@@ -694,6 +743,7 @@ module.exports = function(crowi) {
694743
newPage.updatedAt = Date.now();
695744
newPage.redirectTo = redirectTo;
696745
newPage.grant = grant;
746+
newPage.status = STATUS_PUBLISHED;
697747
newPage.grantedUsers = [];
698748
newPage.grantedUsers.push(user);
699749

@@ -743,6 +793,27 @@ module.exports = function(crowi) {
743793
});
744794
};
745795

796+
pageSchema.statics.deletePage = function(pageData, user, options) {
797+
var Page = this
798+
, newPath = Page.getDeletedPageName(pageData.path)
799+
;
800+
if (Page.isDeletableName(pageData.path)) {
801+
return new Promise(function(resolve, reject) {
802+
Page.updatePageProperty(pageData, {status: STATUS_DELEDED})
803+
.then(function(pageData) {
804+
return Page.rename(pageData, newPath, user, {createRedirectPage: true})
805+
}).then(function(pageData) {
806+
resolve(pageData);
807+
}).catch(reject);
808+
});
809+
} else {
810+
return Promise.reject('Page is not deletable.');
811+
}
812+
};
813+
814+
pageSchema.statics.revertDeletedPage = function(pageData, user, options) {
815+
};
816+
746817
pageSchema.statics.rename = function(pageData, newPagePath, user, options) {
747818
var Page = this
748819
, Revision = crowi.model('Revision')
@@ -772,10 +843,6 @@ module.exports = function(crowi) {
772843
});
773844
};
774845

775-
pageSchema.statics.deletePage = function(pageData, options) {
776-
var Page = this,
777-
};
778-
779846
pageSchema.statics.getHistories = function() {
780847
// TODO
781848
return;

lib/routes/page.js

+20-10
Original file line numberDiff line numberDiff line change
@@ -238,18 +238,19 @@ module.exports = function(crowi, app) {
238238

239239
res.locals.path = path;
240240

241-
// pageShow は /* にマッチしてる最後の砦なので、creatableName でない routing は
242-
// これ以前に定義されているはずなので、こうしてしまって問題ない。
243-
if (!Page.isCreatableName(path)) {
244-
debug('Page is not creatable name.', path);
245-
res.redirect('/');
246-
return ;
247-
}
248-
249241
Page.findPage(path, req.user, req.query.revision)
250242
.then(function(page) {
251243
debug('Page found', page._id, page.path);
252244

245+
// pageShow は /* にマッチしてる最後の砦なので、creatableName でない routing は
246+
// これ以前に定義されているはずなので、こうしてしまって問題ない。
247+
if (!Page.isCreatableName(path) && page.isDeleted()) {
248+
// 削除済みページの場合 /trash 以下に移動しているので creatableName になっていないので、表示を許可
249+
debug('Page is not creatable name.', path);
250+
res.redirect('/');
251+
return ;
252+
}
253+
253254
if (isMarkdown) {
254255
res.set('Content-Type', 'text/plain');
255256
return res.send(page.revision.body);
@@ -300,6 +301,7 @@ module.exports = function(crowi, app) {
300301
// set to render
301302
res.locals.pageForm = pageForm;
302303

304+
// 削除済みページはここで編集不可判定される
303305
if (!Page.isCreatableName(path)) {
304306
res.redirect(redirectPath);
305307
return ;
@@ -597,10 +599,18 @@ module.exports = function(crowi, app) {
597599
var pageId = req.body.page_id;
598600
var previousRevision = req.body.revision_id || null;
599601

600-
Page.findPageByIdAndGrantedUser(id, req.user)
602+
Page.findPageByIdAndGrantedUser(pageId, req.user)
601603
.then(function(pageData) {
602-
return Page.removePage(pageData);
604+
return Page.deletePage(pageData, req.user);
603605
}).then(function(data) {
606+
debug('Page deleted', data);
607+
var result = {};
608+
result.page = pageData;
609+
610+
return res.json(ApiResponse.success(result));
611+
}).catch(function(err) {
612+
debug('Error occured while get setting', err);
613+
return res.json(ApiResponse.error('Failed to delete page.'));
604614
});
605615
};
606616

lib/util/search.js

+4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ SearchClient.prototype.shouldIndexed = function(page) {
4646
return false;
4747
}
4848

49+
if (page.isDeleted()) {
50+
return false;
51+
}
52+
4953
return true;
5054
};
5155

lib/views/layout/layout.html

+2
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@
104104
<li class="divider"></li>
105105
<li><a href="/me"><i class="fa fa-gears"></i> ユーザー設定</a></li>
106106
<li class="divider"></li>
107+
<li><a href="/trash/"><i class="fa fa-trash-o"></i> 削除済みページ</a></li>
108+
<li class="divider"></li>
107109
<li><a href="/logout"><i class="fa fa-sign-out"></i> ログアウト</a></li>
108110
{# <li><a href="#">今日の日報を作成</a></li> #}
109111
{# <li class="divider"></li> #}

lib/views/modal/widget_delete.html

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
<div class="modal-dialog">
33
<div class="modal-content">
44

5-
<form role="form" id="deletePageForm" onsubmit="return false;">
5+
<form role="form" id="delete-page-form" onsubmit="return false;">
66

77
<div class="modal-header">
88
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
9-
<h4 class="modal-title">Delete Page</h4>
9+
<h4 class="modal-title"><i class="fa fa-trash-o"></i> Delete Page</h4>
1010
</div>
1111
<div class="modal-body">
1212
<ul>
13-
<li>You can’t undo this action.</li>
13+
<li>This page will be moved to the trash.</li>
1414
</ul>
1515
<div class="form-group">
1616
<label for="">This page:</label><br>
1717
<code>{{ page.path }}</code>
1818
</div>
1919
</div>
2020
<div class="modal-footer">
21-
<p><small class="pull-left" id="newPageNameCheck"></small></p>
21+
<p><small class="pull-left" id="delete-errors"></small></p>
2222
<input type="hidden" name="path" value="{{ page.path }}">
2323
<input type="hidden" name="page_id" value="{{ page._id.toString() }}">
2424
<input type="hidden" name="revision_id" value="{{ page.revision._id.toString() }}">

lib/views/page.html

+14-1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ <h1 class="title" id="revision-path">{{ path|insertSpaceToEachSlashes }}</h1>
5656

5757
<ul class="nav nav-tabs hidden-print">
5858

59+
{% if page.isDeleted() %}
60+
<li class="">
61+
<a href="#revision-body" data-toggle="tab">
62+
<i class="fa fa-trash-o" aria-hidden="true"></i> This page is in the trash.
63+
</a>
64+
</li>
65+
{% endif %}
66+
67+
{% if not page.isDeleted() %}
5968
<li class=" {% if not req.body.pageForm %}active{% endif %}" data-toggle="tooltip" {# data-title="あなたの 確認待ち です" title="" data-placement="bottom" data-trigger="manual" data-tooltip-stay #}>
6069
<a href="#revision-body" data-toggle="tab">
6170
<i class="fa fa-magic"></i>
@@ -83,13 +92,15 @@ <h1 class="title" id="revision-path">{{ path|insertSpaceToEachSlashes }}</h1>
8392
{% if page %}
8493
<li class="pull-right"><a href="#revision-history" data-toggle="tab"><i class="fa fa-history"></i> History</a></li>
8594
{% endif %}
95+
96+
{% endif %}
8697
</ul>
8798

8899
{% include 'modal/widget_rename.html' %}
89100
{% include 'modal/widget_delete.html' %}
90101

91102
<div class="tab-content wiki-content">
92-
{% if req.query.renamed %}
103+
{% if req.query.renamed and not page.isDeleted() %}
93104
<div class="alert alert-info">
94105
<strong>移動しました: </strong> このページは <code>{{ req.query.renamed }}</code> から移動しました。
95106
</div>
@@ -120,8 +131,10 @@ <h1 class="title" id="revision-path">{{ path|insertSpaceToEachSlashes }}</h1>
120131
</div>
121132

122133
{# edit form #}
134+
{% if not page.isDeleted() %}
123135
<div class="edit-form tab-pane {% if req.body.pageForm %}active{% endif %}" id="edit-form">
124136
{% include '_form.html' %}
137+
{% endif %}
125138
</div>
126139

127140
{# raw revision history #}

resource/js/crowi.js

+21
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ $(function() {
298298
return false;
299299
});
300300

301+
// rename
301302
$('#renamePage').on('shown.bs.modal', function (e) {
302303
$('#newPageName').focus();
303304
});
@@ -327,6 +328,26 @@ $(function() {
327328
return false;
328329
});
329330

331+
// delete
332+
$('#delete-page-form').submit(function(e) {
333+
$.ajax({
334+
type: 'POST',
335+
url: '/_api/pages.remove',
336+
data: $('#delete-page-form').serialize(),
337+
dataType: 'json'
338+
}).done(function(res) {
339+
if (!res.ok) {
340+
$('#delete-errors').html('<i class="fa fa-times-circle"></i> ' + res.error);
341+
$('#delete-errors').addClass('alert-danger');
342+
} else {
343+
var page = res.page;
344+
top.location.href = page.path;
345+
}
346+
});
347+
348+
return false;
349+
});
350+
330351
$('#create-portal-button').on('click', function(e) {
331352
$('.portal').removeClass('hide');
332353
$('.content-main').addClass('on-edit');

0 commit comments

Comments
 (0)