Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into en
Browse files Browse the repository at this point in the history
  • Loading branch information
kabalin committed Jan 8, 2024
2 parents 5801264 + cf35afb commit a98eb5d
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 37 deletions.
4 changes: 2 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -736,8 +736,8 @@ module.exports = {
'no-underscore-dangle': [2, { 'allow': [
'_id', '__get__', '__set__', '__RewireAPI__', '__Rewire__', '__ResetDependency__', '__GetDependency__',
] }],
// Max assertions is 10 and warning rather than error.
'jest/max-expects': [1, { 'max': 10 }],
// Max assertions is 20 and warning rather than error.
'jest/max-expects': [1, { 'max': 20 }],
// We are not using TypeScript
'jest/no-untyped-mock-factory': 0,
},
Expand Down
121 changes: 121 additions & 0 deletions controllers/__tests__/comment.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* Copyright: The PastVu contributors.
* GNU Affero General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/agpl.txt)
*/

import { CommentN } from '../../models/Comment';
import admin from '../admin';
import comment from '../comment';
import testHelpers from '../../tests/testHelpers';

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

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

describe('create for 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('create', async () => {
expect.assertions(3);

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

// Create two comments.
const result = await comment.create(data);

expect(result.comment.txt).toMatch(data.txt);
expect(result.comment.user).toMatch('user1');

await expect(CommentN.count({ obj: news })).resolves.toBe(1);
});
});

describe('retrive', () => {
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('give news comments for user', async () => {
expect.assertions(17);

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

// Create 4 comments.
const comment0 = await comment.create(data);
const comment1 = await comment.create(data);

data.parent = comment1.comment.cid;
data.level = comment1.comment.level + 1;

const comment2 = await comment.create(data);

data.parent = comment2.comment.cid;
data.level = comment2.comment.level + 1;

const comment3 = await comment.create(data);

// Sanity check.
await expect(CommentN.count({ obj: news })).resolves.toBe(4);

const comments = await comment.giveForUser({ login: 'user1', type: 'news' });

expect(comments.type).toMatch('news');
expect(comments.countActive).toBe(4);
expect(comments.objs[news.cid].cid).toStrictEqual(news.cid);
expect(comments.objs[news.cid].ccount).toBe(4);
// Comment 0 - no child, waits answer.
expect(comments.comments[3].cid).toStrictEqual(comment0.comment.cid);
expect(comments.comments[3].hasChild).toBeFalsy();
expect(comments.comments[3].waitsAnswer).toBeTruthy();
// Comment 1 - has child, does not wait answer.
expect(comments.comments[2].cid).toStrictEqual(comment1.comment.cid);
expect(comments.comments[2].hasChild).toBeTruthy();
expect(comments.comments[2].waitsAnswer).toBeFalsy();
// Comment 2 - has child, does not wait answer.
expect(comments.comments[1].cid).toStrictEqual(comment2.comment.cid);
expect(comments.comments[1].hasChild).toBeTruthy();
expect(comments.comments[1].waitsAnswer).toBeFalsy();
// Comment 3 - no child, waits answer.
expect(comments.comments[0].cid).toStrictEqual(comment3.comment.cid);
expect(comments.comments[0].hasChild).toBeFalsy();
expect(comments.comments[0].waitsAnswer).toBeTruthy();
});
});
});
56 changes: 36 additions & 20 deletions controllers/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -722,9 +722,36 @@ async function giveForUser({ login, page = 1, type = 'photo', active = true, del
}

const fields = { _id: 0, lastChanged: 1, cid: 1, obj: 1, stamp: 1, txt: 1, 'del.origin': 1 };
const options = { lean: true, sort: { stamp: -1 }, skip: page * commentsUserPerPage, limit: commentsUserPerPage };
const options = { sort: { stamp: -1 }, skip: page * commentsUserPerPage, limit: commentsUserPerPage };

comments = await commentModel.find(query, fields, options).exec();
if (!iAm.registered) {
comments = await commentModel.find(query, fields, options).lean().exec();
} else {
fields.hasChild = 1;
comments = await commentModel.aggregate([
{
'$match': query,
},
{
'$lookup': {
'from': commentModel.collection.collectionName,
'localField': 'cid',
'foreignField': 'parent',
'as': 'children',
},
},
{
'$addFields': {
'hasChild': {
$gt: [{ $size: '$children' }, 0],
},
},
},
{
'$project': fields,
},
]).sort(options.sort).skip(options.skip).limit(options.limit).exec();
}
}

if (_.isEmpty(comments)) {
Expand Down Expand Up @@ -757,18 +784,6 @@ async function giveForUser({ login, page = 1, type = 'photo', active = true, del

if (type === 'photo' && iAm.registered) {
await this.call('photo.fillPhotosProtection', { photos: objs, setMyFlag: true });

for (const obj of objs) {
objFormattedHashCid[obj.cid] = objFormattedHashId[obj._id] = obj;
obj._id = undefined;
obj.user = undefined;
obj.mime = undefined;
}
} else {
for (const obj of objs) {
objFormattedHashCid[obj.cid] = objFormattedHashId[obj._id] = obj;
obj._id = undefined;
}
}

for (const obj of objs) {
Expand All @@ -780,6 +795,9 @@ async function giveForUser({ login, page = 1, type = 'photo', active = true, del

// For each comment check object exists and assign to comment its cid
for (const comment of comments) {
// Mark those awaiting response.
comment.waitsAnswer = comment.hasChild !== undefined && !comment.hasChild;

const obj = objFormattedHashId[comment.obj];

if (obj !== undefined) {
Expand Down Expand Up @@ -926,7 +944,7 @@ async function create(data) {
throw obj.nocomments ? new NoticeError(constantsError.COMMENT_NOT_ALLOWED) : new AuthorizationError();
}

if (data.parent && (!parent || parent.del || parent.level >= 9 || data.level !== (parent.level || 0) + 1)) {
if (data.parent && (!parent || parent.del || parent.level >= 9 || data.level !== parent.level + 1)) {
throw new NoticeError(constantsError.COMMENT_WRONG_PARENT);
}

Expand All @@ -952,9 +970,11 @@ async function create(data) {
}
}

comment.level = data.level ?? 0;

if (data.parent) {
comment.parent = data.parent;
comment.level = data.level;
comment.level = data.level ?? parent.level + 1;
}

if (fragAdded) {
Expand Down Expand Up @@ -998,10 +1018,6 @@ async function create(data) {
comment.obj = objCid;
comment.can = {};

if (comment.level === undefined) {
comment.level = 0;
}

session.emitUser({ usObj: iAm, excludeSocket: socket });
subscrController.commentAdded(obj._id, iAm.user, stamp);

Expand Down
8 changes: 5 additions & 3 deletions public/js/lib/leaflet/extends/L.Google.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
*/

// Google layer plugin wrapper. Loads Google Maps library with API key included.
define(['Params', 'leaflet', 'leaflet-plugins/lru', 'leaflet-plugins/Leaflet.GoogleMutant'], function (P, L) {
define(['Params', 'leaflet', 'leaflet-plugins/lru', 'leaflet-plugins/Leaflet.GoogleMutant'], function (P, L, lru) {
const keyParam = P.settings.publicApiKeys.googleMaps.length ? '&key=' + P.settings.publicApiKeys.googleMaps : '';
const url = 'https://maps.googleapis.com/maps/api/js?v=weekly&region=RU' + keyParam;

// Load Google Maps API library asynchronously.
require(['async!' + url]);

L.GridLayer.GoogleMutant.addInitHook(function() {
require(['async!' + url]);
});
return function (options) {
options = options || {};
options.lru = new lru.LRUMap(100); // Tile LRU cache.

return new L.GridLayer.GoogleMutant(options);
};
Expand Down
5 changes: 2 additions & 3 deletions public/js/lib/leaflet/plugins/Leaflet.GoogleMutant.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ this stuff is worth it, you can buy me a beer in return.
*/

//import { LRUMap } from "./lru_map.js";
// We have to use requirejs to load module, ES6 syntax won't work here.
const { LRUMap } = require('leaflet-plugins/lru');
// LRU is passed in options.

function waitForAPI(callback, context) {
let checkCounter = 0,
Expand Down Expand Up @@ -47,7 +46,7 @@ L.GridLayer.GoogleMutant = L.GridLayer.extend({

// Couple data structures indexed by tile key
this._tileCallbacks = {}; // Callbacks for promises for tiles that are expected
this._lru = new LRUMap(100); // Tile LRU cache
this._lru = options.lru; // Tile LRU cache

this._imagesPerTile = this.options.type === "hybrid" ? 2 : 1;

Expand Down
8 changes: 0 additions & 8 deletions public/style/comment/comments.less
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
@import '../_vars.less';
@import '../bs/variables.less';
@import '../bs/mixins.less';
@import '../bs/badges.less';

@headColor: #677A8F;
@headColorHover: @MainBlueColor;
Expand Down Expand Up @@ -136,13 +135,6 @@

.levelLooping(0, 58);

.badge {
font-size: 11px;
font-weight: normal;
color: #f2f2f2;
background-color: rgba(85, 85, 85, 80%);
}

&.isnew {
padding-left: 5px;
border-width: 0 0 0 1px;
Expand Down
9 changes: 9 additions & 0 deletions public/style/common.less
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@import '_vars.less';
@import 'fonts/fontU.less';
@import 'bs/bootstrap.less';
@import 'bs/badges.less';

@-webkit-keyframes fadeIn {
0% { opacity: 0; }
Expand Down Expand Up @@ -480,6 +481,14 @@ body {
}
}

// Badges
.badge-latest {
font-size: 11px;
font-weight: normal;
color: #f2f2f2;
background-color: rgba(85, 85, 85, 80%);
}

// Tooltip
.tltp {
position: absolute;
Expand Down
10 changes: 9 additions & 1 deletion views/module/user/comments.pug
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
.dotDelimeter ·
.commentChanged(title="Show history of changes", data-bind="text: ($data.del ? 'Removed at ' : 'Changed at ') + moment($data.lastChanged).calendar().toLowerCase(), click: function () {$parent.showHistory($data.obj.cid, $data.cid)}")
// /ko
//ko if: $data.waitsAnswer
.dotDelimeter ·
.badge.badge-latest Awaiting answer
// /ko
a.commentText(data-bind="attr: {href: $data.link}, html: $data.txt")
| </script>

Expand All @@ -58,6 +62,10 @@
.dotDelimeter ·
.commentChanged(title="Show history of changes", data-bind="text: ($data.del ? 'Removed at ' : 'Changed at ') + moment($data.lastChanged).calendar().toLowerCase(), click: function () {$parent.showHistory($data.obj.cid, $data.cid)}")
// /ko
//ko if: $data.waitsAnswer
.dotDelimeter ·
.badge.badge-latest Awaiting answer
// /ko
a.commentText(style="margin-left:29px", data-bind="attr: {href: $data.link}, html: $data.txt")
| </script>

Expand All @@ -70,4 +78,4 @@
// /ko
li.edge(data-bind="css: {disabled: !pageHasNext()}"): a(data-bind="attr: {href: pageUrl() + '/' + (page() + 1) + pageQuery()}", title="Next page") &raquo;
li.edge(data-bind="css: {disabled: page() === pageLast()}"): a(data-bind="attr: {href: pageUrl() + '/' + pageLast() + pageQuery()}", title="Last page") &raquo;&raquo;
| </script>
| </script>

0 comments on commit a98eb5d

Please sign in to comment.