You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
3.2 KiB
125 lines
3.2 KiB
// resource.js
|
|
// Copyright (C) 2022 DTP Technologies, LLC
|
|
// License: Apache-2.0
|
|
|
|
'use strict';
|
|
|
|
const { SiteService } = require('../../lib/site-lib');
|
|
|
|
const geoip = require('geoip-lite');
|
|
|
|
const mongoose = require('mongoose');
|
|
|
|
const ResourceView = mongoose.model('ResourceView');
|
|
const ResourceVisit = mongoose.model('ResourceVisit');
|
|
|
|
class ResourceService extends SiteService {
|
|
|
|
constructor (dtp) {
|
|
super(dtp, module.exports);
|
|
this.populateResourceView = [
|
|
{
|
|
path: 'resource',
|
|
},
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Records 24-hour unique view counts for a given resource happening on a
|
|
* given ExpressJS Request. Views are uniqued by stripping time from the
|
|
* current Date, and upserting a tracking object in MongoDB.
|
|
*
|
|
* @param {Request} req
|
|
* @param {String} resourceType 'Post', 'Page', or 'Newsletter'
|
|
* @param {mongoose.Types.ObjectId} resourceId The _id of the object for which
|
|
* a view is being tracked.
|
|
*/
|
|
async recordView (req, resourceType, resourceId) {
|
|
const Model = mongoose.model(resourceType);
|
|
const modelUpdate = { $inc: { } };
|
|
|
|
const NOW = new Date();
|
|
const CURRENT_DAY = new Date(NOW);
|
|
CURRENT_DAY.setHours(0, 0, 0, 0);
|
|
|
|
let uniqueKey = req.ip.toString().trim().toLowerCase();
|
|
if (req.user) {
|
|
uniqueKey += `:user:${req.user._id.toString()}`;
|
|
}
|
|
|
|
const response = await ResourceView.updateOne(
|
|
{
|
|
created: CURRENT_DAY,
|
|
resourceType,
|
|
resource: resourceId,
|
|
uniqueKey,
|
|
},
|
|
{
|
|
$inc: { 'stats.visitCount': 1 },
|
|
},
|
|
{ upsert: true },
|
|
);
|
|
|
|
if (response.upsertedCount > 0) {
|
|
modelUpdate.$inc['stats.uniqueViewCount'] = 1;
|
|
}
|
|
|
|
/*
|
|
* Record the ResourceVisit
|
|
*/
|
|
const visit = new ResourceVisit();
|
|
|
|
visit.created = NOW;
|
|
visit.resourceType = resourceType;
|
|
visit.resource = resourceId;
|
|
|
|
if (req.user) {
|
|
visit.user = req.user._id;
|
|
}
|
|
|
|
/*
|
|
* We geo-analyze (but do not store) the IP address.
|
|
*/
|
|
const ipAddress = req.ip;
|
|
const geo = geoip.lookup(ipAddress);
|
|
if (geo) {
|
|
visit.geoip = {
|
|
country: geo.country,
|
|
region: geo.region,
|
|
eu: geo.eu,
|
|
timezone: geo.timezone,
|
|
city: geo.city,
|
|
};
|
|
if (Array.isArray(geo.ll) && (geo.ll.length === 2)) {
|
|
visit.geoip.location = {
|
|
type: 'Point',
|
|
coordinates: geo.ll,
|
|
};
|
|
}
|
|
}
|
|
|
|
await visit.save();
|
|
|
|
modelUpdate.$inc['stats.totalVisitCount'] = 1;
|
|
await Model.updateOne({ _id: resourceId }, modelUpdate);
|
|
}
|
|
|
|
async remove (resourceType, resource) {
|
|
this.log.debug('removing resource view records', { resourceType, resourceId: resource._id });
|
|
await ResourceView.deleteMany({ resource: resource._id });
|
|
|
|
this.log.debug('removing resource visit records', { resourceType, resourceId: resource._id });
|
|
await ResourceVisit.deleteMany({ resource: resource._id });
|
|
|
|
this.log.debug('removing resource', { resourceType, resourceId: resource._id });
|
|
const Model = mongoose.model(resourceType);
|
|
await Model.deleteOne({ _id: resource._id });
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
logId: 'resource',
|
|
index: 'resource',
|
|
className: 'ResourceService',
|
|
create: (dtp) => { return new ResourceService(dtp); },
|
|
};
|