Skip to content

Commit

Permalink
Implement news deletion.
Browse files Browse the repository at this point in the history
  • Loading branch information
kabalin committed Nov 4, 2023
1 parent c0ca5a4 commit 38a4ad8
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 6 deletions.
146 changes: 146 additions & 0 deletions controllers/__tests__/admin.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/**
* Copyright: The PastVu contributors.
* GNU Affero General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/agpl.txt)
*/

import { News } from '../../models/News';
import { CommentN } from '../../models/Comment';
import { BadParamsError, AuthorizationError, NotFoundError, NoticeError } from '../../app/errors';
import constants from '../../app/errors/constants';
import admin from '../admin';
import comment from '../comment';
import testHelpers from '../../tests/testHelpers';

describe('admin', () => {
beforeEach(async () => {
// Mock non-registerd user handshake.
admin.handshake = { 'usObj': { 'isAdmin': true } };
});

afterEach(() => {
// Delete handshake.
delete admin.handshake;
});

describe('save or create news', () => {
it('should create and update news', async () => {
expect.assertions(2);

const data = { pdate: new Date(), 'title': 'Test news', 'txt': 'Test news content' };
let result = await admin.saveOrCreateNews(data);

expect(result.news).toMatchObject(data);

// Update same record.
data.title = 'Test news updated';
data.txt = 'Test news content updated';
data.cid = result.news.cid;
result = await admin.saveOrCreateNews(data);

expect(result.news).toMatchObject(data);
});

it('should create news with commenting disabled', async () => {
expect.assertions(2);

const data = { 'title': 'Test news', 'txt': 'Test news content', nocomments: true };
const result = await admin.saveOrCreateNews(data);

expect(result.news).toMatchObject(data);
expect(result.news.nocomments).toBeTruthy();
});

it('throws on non-admin use', async () => {
expect.assertions(1);

// Reset handshake.
admin.handshake = { 'usObj': { 'isAdmin': false } };

const data = { 'title': 'Test news', 'txt': 'Test news content' };

expect(() => admin.saveOrCreateNews(data)).toThrow(new AuthorizationError());
});

it('throws on empty text', async () => {
expect.assertions(1);

const data = { 'title': 'Test news' };

expect(() => admin.saveOrCreateNews(data)).toThrow(new BadParamsError());
});

it('throws on non-existing news', async () => {
expect.assertions(1);

const data = { cid: 1000, 'title': 'Test news', 'txt': 'Test news content' };

await expect(admin.saveOrCreateNews(data)).rejects.toThrow(new NotFoundError(constants.NO_SUCH_NEWS));
});
});

describe('delete news', () => {
let news;

beforeEach(async () => {
const data = { pdate: new Date(), 'title': 'Test news', 'txt': 'Test news content' };

({ news } = await admin.saveOrCreateNews(data));

const user = await testHelpers.createUser({ login: 'user1', pass: 'pass1' });

// Mock non-registered user handshake.
comment.handshake = { 'usObj': { 'isAdmin': true, 'registered': true, user } };
});

afterEach(() => {
// Delete handshake.
delete comment.handshake;
});

it('delete news', async () => {
expect.assertions(2);

// Delete news record.
const del = await admin.deleteNews(news);

expect(del).toMatchObject({});
await expect(News.findOne({ cid: news.cid })).resolves.toBeNull();
});

it('throws on non-admin use', async () => {
expect.assertions(1);

// Reset handshake.
admin.handshake = { 'usObj': { 'isAdmin': false } };

await expect(admin.deleteNews(news)).rejects.toThrow(new AuthorizationError());
});

it('throws on missing cid', async () => {
expect.assertions(1);

news.cid = undefined;

await expect(admin.deleteNews(news)).rejects.toThrow(new BadParamsError());
});

it('throws on non-existing news', async () => {
expect.assertions(1);

const data = { cid: 1000 };

await expect(admin.deleteNews(data)).rejects.toThrow(new NotFoundError(constants.NO_SUCH_NEWS));
});

it('throws on non-zero comments', async () => {
expect.assertions(2);

const data = { txt: 'news comment', type: 'news', obj: news.cid };

await comment.create(data);

await expect(CommentN.count({ obj: news })).resolves.toBe(1);
await expect(admin.deleteNews(news)).rejects.toThrow(new NoticeError(constants.NEWS_CONTAINS_COMMENTS));
});
});
});
28 changes: 28 additions & 0 deletions controllers/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,32 @@ async function saveNews(iAm, { cid, pdate, tdate, title, notice, txt, nocomments
return { news: novel };
}

async function deleteNews(data) {
const { handshake: { usObj: iAm } } = this;

if (!iAm.isAdmin) {
throw new AuthorizationError();
}

if (!data.cid) {
throw new BadParamsError();
}

const novel = await News.findOne({ cid: data.cid }).exec();

if (!novel) {
throw new NotFoundError(constantsError.NO_SUCH_NEWS);
}

if (novel.ccount > 0) {
throw new NoticeError(constantsError.NEWS_CONTAINS_COMMENTS);
}

await News.deleteOne({ cid: data.cid }).exec();

return {};
}

function getOnlineStat() {
const { handshake: { usObj: iAm } } = this;

Expand Down Expand Up @@ -220,9 +246,11 @@ async function saveUserCredentials({ login, role, regions }) {
getOnlineStat.isPublic = true;
saveOrCreateNews.isPublic = true;
saveUserCredentials.isPublic = true;
deleteNews.isPublic = true;

export default {
getOnlineStat,
saveOrCreateNews,
saveUserCredentials,
deleteNews,
};
3 changes: 2 additions & 1 deletion controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,9 @@ const giveIndexNews = (function () {
// News archive
async function giveAllNews() {
const { handshake: { usObj: iAm } } = this;
// Admin can see all news including scheduled ones.
const news = await News.find(
{ pdate: { $lte: new Date() } },
iAm.isAdmin ? {} : { pdate: { $lte: new Date() } },
{ cdate: 0, tdate: 0, nocomments: 0 },
{ lean: true, sort: { pdate: -1 } }
).populate({ path: 'user', select: { _id: 0, login: 1, avatar: 1, disp: 1 } }).exec();
Expand Down
36 changes: 35 additions & 1 deletion public/js/module/admin/newsEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,23 @@ define([
},
routeHandler: function () {
const cid = Number(globalVM.router.params().cid);
const action = globalVM.router.params().action;

this.createMode(!cid);
if (action === 'delete') {
this.getOneNews(cid, function () {
this.deleteNews();
}, this);
}

this.createMode(action === 'create');

if (!this.createMode()) {
// Edit news.
this.getOneNews(cid, function () {
this.fillData();
}, this);
} else {
// Create news.
this.resetData();
}
},
Expand Down Expand Up @@ -167,6 +176,31 @@ define([
this.news.tdate('');
}
},
deleteNews: function () {
if (this.news.ccount && this.news.ccount() > 0) {
noties.error({
message: 'Новость содержит комментарии и не может быть удалена',
});
} else {
const cid = this.news.cid();

noties.confirm({
message: `Новость "${this.news.title()}" будет удалена`,
onOk: function (confirmer) {
confirmer.close();
socket.run('admin.deleteNews', { cid }, true)
.then(function () {
noties.alert({
message: 'Новость удалена',
type: 'success',
layout: 'topRight',
});
globalVM.router.navigate('/admin/news/');
});
},
});
}
},

toggleNotice: function () {
if (this.noticeExists()) {
Expand Down
4 changes: 2 additions & 2 deletions public/js/module/appAdmin.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ require([
params = { section: section };
modules.push({ module: 'm/admin/main', container: '#bodyContainer' });
} else if (section === 'news') {
if (param1 === 'create' || param1 === 'edit') {
params = { section: section, cid: param2 };
if (param1 === 'create' || param1 === 'edit' || param1 === 'delete') {
params = { section: section, cid: param2, action: param1 };
modules.push({ module: 'm/admin/newsEdit', container: '#bodyContainer' });
} else {
params = { section: section, cid: param1 };
Expand Down
4 changes: 4 additions & 0 deletions public/style/diff/newsList.less
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@
}
}
}

&.future {
background-color: darken(@body-bg, 10%);
}
}
}
}
10 changes: 8 additions & 2 deletions views/module/diff/newsList.pug
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
.news
//ko foreach: news
hr
.novel.clearfix
.novel.clearfix(data-bind="css: {future: new Date($data.pdate) > new Date()}")
.newsLeft
.newsAvatar.fringe(data-bind="attr: {href: '/u/' + $data.user.login}")
img(data-bind="attr: {src: $data.user.avatar}")
Expand All @@ -28,8 +28,14 @@
span.glyphicon.glyphicon-pencil
| Редактировать
// /ko
//ko if: $parent.canEdit() && !$data.ccount
.dotDelimeter ·
a.newsEdit(data-bind="attr: {href: '/admin/news/delete/' + $data.cid}")
span.glyphicon.glyphicon-trash
| Delete
// /ko
.newsNotice(data-bind="html: $data.notice, css: {expandable: $data.expand}")
//ko if: $data.expand
a.newsExpand(data-bind="attr: {href: '/news/' + $data.cid}") [Читать полностью..]
// /ko
// /ko
// /ko

0 comments on commit 38a4ad8

Please sign in to comment.