Profile pages now display user status.
This commit is contained in:
parent
6445950f90
commit
1384b02f4d
11 changed files with 119 additions and 5 deletions
|
|
@ -18,6 +18,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
|||
const {validationResult, matchedData} = require('express-validator');
|
||||
|
||||
//local imports
|
||||
const presenceUtils = require('../../utils/presenceUtils');
|
||||
const {userModel} = require('../../schemas/user/userSchema');
|
||||
const {exceptionHandler, errorHandler} = require('../../utils/loggerUtils');
|
||||
|
||||
|
|
@ -30,7 +31,10 @@ module.exports.get = async function(req, res){
|
|||
const data = matchedData(req);
|
||||
const profile = await userModel.findProfile({user: data.user});
|
||||
|
||||
return res.render('partial/panels/profile', {profile});
|
||||
//Pull presence (should be quick since everyone whos been on since last startup will be backed in RAM)
|
||||
const presence = await presenceUtils.getPresence(profile.user);
|
||||
|
||||
return res.render('partial/panels/profile', {profile, presence});
|
||||
}else{
|
||||
res.status(400);
|
||||
return res.send({errors: validResult.array()})
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
|||
//Local Imports
|
||||
const {userModel} = require('../schemas/user/userSchema');
|
||||
const csrfUtils = require('../utils/csrfUtils');
|
||||
const presenceUtils = require('../utils/presenceUtils');
|
||||
const {exceptionHandler, errorHandler} = require('../utils/loggerUtils');
|
||||
|
||||
//Config
|
||||
|
|
@ -34,11 +35,15 @@ module.exports.get = async function(req, res){
|
|||
//If we have a user, check if the is looking at their own profile
|
||||
const selfProfile = req.session.user ? profile.user == req.session.user.user : false;
|
||||
|
||||
//Pull presence (should be quick since everyone whos been on since last startup will be backed in RAM)
|
||||
const presence = await presenceUtils.getPresence(profile.user);
|
||||
|
||||
res.render('profile', {
|
||||
instance: config.instanceName,
|
||||
user: req.session.user,
|
||||
profile,
|
||||
selfProfile,
|
||||
presence,
|
||||
csrfToken: csrfUtils.generateToken(req)
|
||||
});
|
||||
}else{
|
||||
|
|
@ -47,6 +52,7 @@ module.exports.get = async function(req, res){
|
|||
user: req.session.user,
|
||||
profile: null,
|
||||
selfProfile: false,
|
||||
presence: null,
|
||||
csrfToken: csrfUtils.generateToken(req)
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ const userSchema = new mongoose.Schema({
|
|||
lastActive: {
|
||||
type: mongoose.SchemaTypes.Date,
|
||||
required: true,
|
||||
default: new Date()
|
||||
default: new Date(0)
|
||||
},
|
||||
rank: {
|
||||
type: mongoose.SchemaTypes.String,
|
||||
|
|
@ -505,6 +505,7 @@ userSchema.methods.getProfile = function(includeEmail = false){
|
|||
id: this.id,
|
||||
user: this.user,
|
||||
date: this.date,
|
||||
lastActive: this.lastActive,
|
||||
tokes: this.tokes,
|
||||
tokeCount: this.getTokeCount(),
|
||||
img: this.img,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ You should have received a copy of the GNU Affero General Public License
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||
|
||||
//local includes
|
||||
const server = require('../server');
|
||||
const userSchema = require('../schemas/user/userSchema');
|
||||
|
||||
//User activity map to keep us from constantly reading off of the DB
|
||||
|
|
@ -23,6 +24,64 @@ let activityMap = new Map();
|
|||
//How much difference between last write and now until we hit the DB again (in millis)
|
||||
//Defaults to two minutes
|
||||
const tolerance = 2 * (60 * 1000);
|
||||
//How long a user has to be in-active to be considered offline
|
||||
//Defaults to five minutes
|
||||
const offlineTimeout = 5 * (60 * 1000);
|
||||
|
||||
module.exports.getPresence = async function(user, userDB){
|
||||
//If we don't have a user
|
||||
if(user == null || user == '' || user == 'Tokebot'){
|
||||
//Drop that shit
|
||||
return;
|
||||
}
|
||||
|
||||
//Set status as offline
|
||||
let status = "Offline"
|
||||
//Attempt to pull from activity map to save on DB pull
|
||||
let activity = activityMap.get(user);
|
||||
//Pull current epoch in millis
|
||||
const now = new Date().getTime();
|
||||
|
||||
//If we couldn't find anything in RAM
|
||||
if(activity == null){
|
||||
//If we wheren't handed a free user doc
|
||||
if(userDB == null){
|
||||
//Pull one from the username
|
||||
userDB = await userSchema.userModel.findOne({user: user});
|
||||
}
|
||||
|
||||
//If for some reason we can't find a user doc
|
||||
if(userDB == null){
|
||||
//Bail with empty status object
|
||||
return {
|
||||
status,
|
||||
activeConnections: [],
|
||||
lastActive: 0
|
||||
}
|
||||
}
|
||||
|
||||
//Pull last active date from userDB
|
||||
activity = userDB.lastActive.getTime();
|
||||
}
|
||||
|
||||
//Pull active connections for user from the channel manager
|
||||
const activeConnections = server.channelManager.getConnections(user);
|
||||
|
||||
//If the user is connected to at least one channel
|
||||
if(activeConnections != null && activeConnections.length > 0){
|
||||
status = "Streaming";
|
||||
//Otherwise, if it's been five minutes
|
||||
}else if(now - activity < offlineTimeout){
|
||||
status = "Recently Active";
|
||||
}
|
||||
|
||||
//Assemble and return status object
|
||||
return {
|
||||
status,
|
||||
activeConnections,
|
||||
lastActive: activity
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.presenceMiddleware = function(req, res, next){
|
||||
//Pull user from session
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
|||
<% }else{ %>
|
||||
<a class="panel profile-link" target="_blank" href="/profile/<%- profile.user %>">View Full Profile<i class="bi-box-arrow-in-up-right"></i></a>
|
||||
<h2 class="panel profile-name"><%- profile.user %></h2>
|
||||
<%- include('../profile/status', {profile, presence, auxClass:"panel"}); %>
|
||||
<img class="panel profile-img" src="<%- profile.img %>">
|
||||
<p class="panel profile-info">Toke Count: <%- profile.tokeCount %></p>
|
||||
<% if(profile.pronouns != '' && profile.pronouns != null){ %>
|
||||
|
|
|
|||
22
src/views/partial/profile/status.ejs
Normal file
22
src/views/partial/profile/status.ejs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<%# Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
||||
<% if(profile.user == "Tokebot"){ %>
|
||||
<p id="profile-status" class="<%- auxClass %> positive profile-status"><span class="bi-record-fill"></span>Perma-Couched</p>
|
||||
<% }else{ %>
|
||||
<% const statusClass = (presence.status == "Streaming") ? "positive" : ((presence.status == "Offline") ? "inactive" : "positive-low");%>
|
||||
<% const curChan = (presence.activeConnections == null || presence.activeConnections.length <= 0) ? '' : (presence.activeConnections.length == 1 ? ` - /c/${presence.activeConnections[0].channel.name}` : " - Multiple Channels"); %>
|
||||
<p id="profile-status" class="<%- auxClass %> <%- statusClass %> profile-status"><span class="bi-record-fill"></span><%- presence.status %><%-curChan%></p>
|
||||
<% } %>
|
||||
|
|
@ -33,6 +33,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
|||
<div class="profile dynamic-container" id="profile-div">
|
||||
<span id="profile-info" class="profile">
|
||||
<h1 class="profile-item" id="profile-username"><%- profile.user %></h1>
|
||||
<%- include('partial/profile/status', {profile, presence, auxClass: ""}); %>
|
||||
<%- include('partial/profile/image', {profile, selfProfile}); %>
|
||||
<%- include('partial/profile/pronouns', {profile, selfProfile}); %>
|
||||
<%- include('partial/profile/signature', {profile, selfProfile}); %>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue