| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 | import { Meteor } from 'meteor/meteor';import Users from '../users';function acceptedIpAddress(ipAddress) {  const trustedIpAddress = process.env.METRICS_ACCEPTED_IP_ADDRESS;  return (    trustedIpAddress !== undefined &&    trustedIpAddress.split(',').includes(ipAddress)  );}function accessToken(req) {  const valid_token = process.env.METRICS_ACCESS_TOKEN;  let token;  if (req.headers && req.headers.authorization) {    var parts = req.headers.authorization.split(" ");    if (parts.length === 2) {      var scheme = parts[0];      var credentials = parts[1];      if (/^Bearer$/i.test(scheme)) {        token = credentials;      }    }  }  if (!token && req.query && req.query.access_token) {    token = req.query.access_token;  }  return (    token !== undefined &&    valid_token !== undefined &&    token == valid_token  );}const getBoardTitleWithMostActivities = (dateWithXdaysAgo, nbLimit) => {  return Promise.await(    Activities.rawCollection()      .aggregate([      {          $match: { modifiedAt: { $gte: dateWithXdaysAgo }}      },      {       $group: { _id: '$boardId', count: { $sum: 1 } }      },      {       $sort: { count: -1 }      },      {       $lookup: { from: 'boards', localField: '_id', foreignField: '_id', as: 'lookup'}      },      {       $project: { "lookup.title":1, "count":1}      }])      .limit(nbLimit).toArray()      );};const getBoards = (boardIds) => {  const ret = ReactiveCache.getBoards({ _id: { $in: boardIds } });  return ret;};Meteor.startup(() => {  WebApp.connectHandlers.use('/metrics', (req, res, next) => {    try {      const ipAddress =        req.headers['x-forwarded-for'] || req.socket.remoteAddress;      // if(process.env.TRUST_PROXY_FORXARD)      // {      //   const ipAddress = req.headers['x-forwarded-for'] || req.socket.remoteAddress      // }else{      //   const ipAddress = req.socket.remoteAddress      // }      // List of trusted ip adress will be found in environment variable "METRICS_ACCEPTED_IP_ADDRESS" (separeted with commas)      if (acceptedIpAddress(ipAddress) || (accessToken(req))) {        let metricsRes = '';        let resCount = 0;        //connected users        metricsRes += '# Number of connected users\n';        // Get number of connected user by using meteor socketJs        const allOpenedSockets = Meteor.server.stream_server.open_sockets;        let connectedUserIds = [];        allOpenedSockets.forEach(          (socket) =>            socket._meteorSession.userId !== null &&            connectedUserIds.push(socket._meteorSession.userId),        );        resCount = connectedUserIds.length; // KPI 1        metricsRes += 'wekan_connectedUsers ' + resCount + '\n';        //registered users        metricsRes += '# Number of registered users\n';        // Get number of registered user        resCount = ReactiveCache.getUsers({}).length; // KPI 2        metricsRes += 'wekan_registeredUsers ' + resCount + '\n';        resCount = 0;        //board numbers        metricsRes += '# Number of registered boards\n';        // Get number of registered boards        resCount = ReactiveCache.getBoards({ archived: false, type: 'board' }).length; // KPI 3        metricsRes += 'wekan_registeredboards ' + resCount + '\n';        resCount = 0;        //board numbers by registered users        metricsRes += '# Number of registered boards by registered users\n';        // Get number of registered boards by registered users        resCount =          ReactiveCache.getBoards({ archived: false, type: 'board' }).length /          ReactiveCache.getUsers({}).length; // KPI 4        metricsRes +=          'wekan_registeredboardsBysRegisteredUsers ' + resCount + '\n';        resCount = 0;        //board numbers with only one member        metricsRes += '# Number of registered boards\n';        // Get board numbers with only one member        resCount = ReactiveCache.getBoards({          archived: false,          type: 'board',          members: { $size: 1 },        }).length; // KPI 5        metricsRes +=          'wekan_registeredboardsWithOnlyOneMember ' + resCount + '\n';        resCount = 0;        // KPI 6 : - store last login date        //         KPI 6 = count where date of last connection > x days        // Cutting in label since 5 days / 10 days / 20 days / 30 days        //Number of users with last connection dated 5 days ago        metricsRes +=          '# Number of users with last connection dated 5 days ago\n';        // Get number of users with last connection dated 5 days ago        let xdays = 5;        let dateWithXdaysAgo = new Date(          new Date() - xdays * 24 * 60 * 60 * 1000,        );        resCount = ReactiveCache.getUsers({          lastConnectionDate: { $gte: dateWithXdaysAgo },        }).length; // KPI 5        metricsRes +=          'wekan_usersWithLastConnectionDated5DaysAgo ' + resCount + '\n';        resCount = 0;        metricsRes +=          '# Number of users with last connection dated 10 days ago\n';        // Get number of users with last connection dated 10 days ago        xdays = 10;        dateWithXdaysAgo = new Date(new Date() - xdays * 24 * 60 * 60 * 1000);        resCount = ReactiveCache.getUsers({          lastConnectionDate: { $gte: dateWithXdaysAgo },        }).length; // KPI 5        metricsRes +=          'wekan_usersWithLastConnectionDated10DaysAgo ' + resCount + '\n';        resCount = 0;        metricsRes +=          '# Number of users with last connection dated 20 days ago\n';        // Get number of users with last connection dated 20 days ago        xdays = 20;        dateWithXdaysAgo = new Date(new Date() - xdays * 24 * 60 * 60 * 1000);        resCount = ReactiveCache.getUsers({          lastConnectionDate: { $gte: dateWithXdaysAgo },        }).length; // KPI 5        metricsRes +=          'wekan_usersWithLastConnectionDated20DaysAgo ' + resCount + '\n';        resCount = 0;        metricsRes +=          '# Number of users with last connection dated 30 days ago\n';        // Get number of users with last connection dated 20 days ago        xdays = 30;        dateWithXdaysAgo = new Date(new Date() - xdays * 24 * 60 * 60 * 1000);        resCount = ReactiveCache.getUsers({          lastConnectionDate: { $gte: dateWithXdaysAgo },        }).length; // KPI 5        metricsRes +=          'wekan_usersWithLastConnectionDated30DaysAgo ' + resCount + '\n';        resCount = 0;        // TO DO:        // connection average: ((disconnection date - last connection date) + (last average)) / 2        // KPI 7 : sum of connection average / number of users (ignore users with 0 average)        metricsRes +=          '# Top 10 boards with most activities dated 30 days ago\n';        //Get top 10 table with most activities in current month        const boardTitleWithMostActivities = getBoardTitleWithMostActivities(          dateWithXdaysAgo,          xdays,        );        const boardWithMostActivities = boardTitleWithMostActivities.map(          (board) => board.lookup[0].title,        );        boardWithMostActivities.forEach((title, index) => {          metricsRes +=            `wekan_top10BoardsWithMostActivities{n="${title}"} ${              index + 1            }` + '\n';        });        res.writeHead(200); // HTTP status        res.end(metricsRes);      } else {        res.writeHead(401); // HTTP status        res.end(          'IpAddress: ' +            ipAddress +            ' is not authorized to perform this action !!\n',        );      }    } catch (e) {      res.writeHead(500); // HTTP status      res.end(e.toString());    }  });});
 |