Skip to content

Commit 97f3d7b

Browse files
committed
first pass
1 parent d19f878 commit 97f3d7b

16 files changed

+4118
-0
lines changed

.eslintrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "nodebb"
3+
}

.gitignore

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
npm-debug.log
2+
node_modules/
3+
sftp-config.json
4+
public/css/*.css
5+
*.sublime-project
6+
*.sublime-workspace
7+
.project
8+
.idea
9+
*.swp
10+
Vagrantfile
11+
.vagrant
12+
provision.sh
13+
*.komodoproject
14+

index.js

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
2+
'use strict';
3+
4+
const querystring = require('querystring');
5+
6+
const _ = require.main.require('lodash');
7+
8+
const db = require.main.require('./src/database');
9+
const routeHelpers = require.main.require('./src/routes/helpers');
10+
const controllerHelpers = require.main.require('./src/controllers/helpers');
11+
const topics = require.main.require('./src/topics');
12+
const groups = require.main.require('./src/groups');
13+
const posts = require.main.require('./src/posts');
14+
const privileges = require.main.require('./src/privileges');
15+
const pagination = require.main.require('./src/pagination');
16+
const meta = require.main.require('./src/meta');
17+
18+
const devTracker = module.exports;
19+
20+
devTracker.init = async function (params) {
21+
routeHelpers.setupPageRoute(params.router, '/dev-tracker', renderDevTracker);
22+
routeHelpers.setupAdminPageRoute(params.router, '/admin/plugins/dev-tracker', renderAdmin);
23+
};
24+
25+
async function renderAdmin(req, res) {
26+
const groupsData = await groups.getNonPrivilegeGroups('groups:createtime', 0, -1);
27+
groupsData.sort((a, b) => b.system - a.system);
28+
res.render('admin/plugins/dev-tracker', { groups: groupsData });
29+
}
30+
31+
async function getDevTrackerGroups() {
32+
const settings = await meta.settings.get('dev-tracker');
33+
let groups = settings.devTrackerGroups || '[]';
34+
try {
35+
groups = JSON.parse(groups);
36+
return groups;
37+
} catch (err) {
38+
console.error(err.stack);
39+
return [];
40+
}
41+
}
42+
43+
async function getDevTrackerUidsFromGroups(groupNames) {
44+
const arrayOfUids = await groups.getMembersOfGroups(groupNames);
45+
return _.uniq(_.flatten(arrayOfUids));
46+
}
47+
48+
async function renderDevTracker(req, res) {
49+
const page = Math.max(1, parseInt(req.query.page, 10) || 1);
50+
const cids = getCidsArray(req.query.cid);
51+
const groupNames = await getDevTrackerGroups();
52+
const currentGroup = req.query.group || '';
53+
let showPosts = parseInt(req.query.posts, 10) === 1;
54+
const showTopics = parseInt(req.query.topics, 10) === 1;
55+
if (!showPosts && !showTopics) {
56+
showPosts = true;
57+
}
58+
59+
const [uids, groupData, categoryData] = await Promise.all([
60+
getDevTrackerUidsFromGroups(currentGroup ? [currentGroup] : groupNames),
61+
groups.getGroupsData(groupNames),
62+
controllerHelpers.getSelectedCategory(cids),
63+
]);
64+
65+
groupData.forEach((group) => {
66+
group.selected = group.name === req.query.group;
67+
group.url = `dev-tracker?${querystring.stringify({ ...req.query, group: group.name })}`;
68+
});
69+
let data = [];
70+
if (showPosts) {
71+
data = await getPosts(req, uids, cids);
72+
} else if (showTopics) {
73+
data = await getTopics(req, uids, cids);
74+
}
75+
76+
delete req.query._;
77+
res.render('dev-tracker', {
78+
showPosts,
79+
showTopics,
80+
posts: data.posts,
81+
topics: data.topics,
82+
groups: groupData,
83+
allCategoriesUrl: `dev-tracker${controllerHelpers.buildQueryString(req.query, 'cid', '')}`,
84+
allGroupsUrl: `dev-tracker${controllerHelpers.buildQueryString(req.query, 'group', '')}`,
85+
selectedGroup: groupData.find(g => g.name === req.query.group),
86+
selectedCategory: categoryData.selectedCategory,
87+
selectedCids: categoryData.selectedCids,
88+
pagination: pagination.create(page, data.pageCount, req.query),
89+
});
90+
}
91+
92+
async function getPosts(req, uids, cids) {
93+
const sets = _.flatten(uids.map((uid) => {
94+
if (cids) {
95+
return cids.map(cid => `cid:${cid}:uid:${uid}:pids`);
96+
}
97+
return `uid:${uid}:posts`;
98+
}));
99+
const allPids = await db.getSortedSetRevRange(sets, 0, 499);
100+
const pids = await privileges.posts.filter('topics:read', allPids, req.uid);
101+
102+
const pageCount = Math.max(1, Math.ceil(pids.length / meta.config.postsPerPage));
103+
const page = Math.max(1, parseInt(req.query.page, 10) || 1);
104+
105+
const start = Math.max(0, (page - 1) * meta.config.postsPerPage);
106+
const stop = start + meta.config.postsPerPage - 1;
107+
const pagePids = page > pageCount ? [] : pids.slice(start, stop + 1);
108+
const postData = await posts.getPostSummaryByPids(pagePids, req.uid, { stripTags: false });
109+
return {
110+
posts: postData,
111+
pageCount,
112+
};
113+
}
114+
115+
async function getTopics(req, uids, cids) {
116+
const sets = _.flatten(uids.map((uid) => {
117+
if (cids) {
118+
return cids.map(cid => `cid:${cid}:uid:${uid}:tids`);
119+
}
120+
return `uid:${uid}:topics`;
121+
}));
122+
const allTids = await db.getSortedSetRevRange(sets, 0, 499);
123+
const tids = await privileges.topics.filterTids('topics:read', allTids, req.uid);
124+
125+
const pageCount = Math.max(1, Math.ceil(tids.length / meta.config.topicsPerPage));
126+
const page = Math.max(1, parseInt(req.query.page, 10) || 1);
127+
128+
const start = Math.max(0, (page - 1) * meta.config.topicsPerPage);
129+
const stop = start + meta.config.topicsPerPage - 1;
130+
const pageTids = page > pageCount ? [] : tids.slice(start, stop + 1);
131+
const topicData = await topics.getTopicsByTids(pageTids, req.uid);
132+
topics.calculateTopicIndices(topicData, start);
133+
return {
134+
topics: topicData,
135+
pageCount,
136+
};
137+
}
138+
139+
function getCidsArray(cid) {
140+
if (cid && !Array.isArray(cid)) {
141+
cid = [cid];
142+
}
143+
return cid && cid.map(cid => parseInt(cid, 10));
144+
}
145+
146+
devTracker.addAdminNavigation = function (header) {
147+
header.plugins.push({
148+
route: '/plugins/dev-tracker',
149+
icon: 'fa-list',
150+
name: 'Dev Tracker',
151+
});
152+
return header;
153+
};
154+
155+
devTracker.defineWidgetAreas = async function (areas) {
156+
areas = areas.concat([
157+
{
158+
name: 'Dev Tracker Page (Header)',
159+
template: 'dev-tracker.tpl',
160+
location: 'header',
161+
},
162+
{
163+
name: 'Dev Tracker Page (Left)',
164+
template: 'dev-tracker.tpl',
165+
location: 'left',
166+
},
167+
{
168+
name: 'Dev Tracker Page (Right)',
169+
template: 'dev-tracker.tpl',
170+
location: 'right',
171+
},
172+
{
173+
name: 'Dev Tracker Page (Footer)',
174+
template: 'dev-tracker.tpl',
175+
location: 'footer',
176+
},
177+
]);
178+
return areas;
179+
};

languages/de/dev-tracker.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"no-posts-found": "No posts found",
3+
"no-topics-found": "No topics found"
4+
}

languages/en-GB/dev-tracker.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"no-posts-found": "No posts found",
3+
"no-topics-found": "No topics found"
4+
}

languages/en-US/dev-tracker.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"no-posts-found": "No posts found",
3+
"no-topics-found": "No topics found"
4+
}

languages/he/dev-tracker.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"no-posts-found": "לא נמצאו פוסטים",
3+
"no-topics-found": "No topics found"
4+
}

languages/tr/dev-tracker.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"no-posts-found": "Gönderi bulunamadı",
3+
"no-topics-found": "Konu bulunamadı"
4+
}

0 commit comments

Comments
 (0)