The DTP Sites web app development engine.
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.
 
 
 
 
 

124 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 = {
slug: 'resource',
name: 'resource',
create: (dtp) => { return new ResourceService(dtp); },
};