Add last login date to users
This commit is contained in:
parent
ee8e602ef9
commit
3cc665f48f
10 changed files with 107 additions and 9 deletions
|
@ -71,6 +71,8 @@ export class User implements UserServerModel {
|
||||||
|
|
||||||
pluginAuth: string | null
|
pluginAuth: string | null
|
||||||
|
|
||||||
|
lastLoginDate: Date | null
|
||||||
|
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
|
|
||||||
constructor (hash: Partial<UserServerModel>) {
|
constructor (hash: Partial<UserServerModel>) {
|
||||||
|
@ -115,6 +117,7 @@ export class User implements UserServerModel {
|
||||||
this.createdAt = hash.createdAt
|
this.createdAt = hash.createdAt
|
||||||
|
|
||||||
this.pluginAuth = hash.pluginAuth
|
this.pluginAuth = hash.pluginAuth
|
||||||
|
this.lastLoginDate = hash.lastLoginDate
|
||||||
|
|
||||||
if (hash.account !== undefined) {
|
if (hash.account !== undefined) {
|
||||||
this.account = new Account(hash.account)
|
this.account = new Account(hash.account)
|
||||||
|
|
|
@ -22,7 +22,7 @@ statsRouter.get('/stats',
|
||||||
async function getStats (req: express.Request, res: express.Response) {
|
async function getStats (req: express.Request, res: express.Response) {
|
||||||
const { totalLocalVideos, totalLocalVideoViews, totalVideos } = await VideoModel.getStats()
|
const { totalLocalVideos, totalLocalVideoViews, totalVideos } = await VideoModel.getStats()
|
||||||
const { totalLocalVideoComments, totalVideoComments } = await VideoCommentModel.getStats()
|
const { totalLocalVideoComments, totalVideoComments } = await VideoCommentModel.getStats()
|
||||||
const { totalUsers } = await UserModel.getStats()
|
const { totalUsers, totalDailyActiveUsers, totalWeeklyActiveUsers, totalMonthlyActiveUsers } = await UserModel.getStats()
|
||||||
const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats()
|
const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats()
|
||||||
const { totalLocalVideoFilesSize } = await VideoFileModel.getStats()
|
const { totalLocalVideoFilesSize } = await VideoFileModel.getStats()
|
||||||
|
|
||||||
|
@ -48,9 +48,15 @@ async function getStats (req: express.Request, res: express.Response) {
|
||||||
totalLocalVideoComments,
|
totalLocalVideoComments,
|
||||||
totalVideos,
|
totalVideos,
|
||||||
totalVideoComments,
|
totalVideoComments,
|
||||||
|
|
||||||
totalUsers,
|
totalUsers,
|
||||||
|
totalDailyActiveUsers,
|
||||||
|
totalWeeklyActiveUsers,
|
||||||
|
totalMonthlyActiveUsers,
|
||||||
|
|
||||||
totalInstanceFollowers,
|
totalInstanceFollowers,
|
||||||
totalInstanceFollowing,
|
totalInstanceFollowing,
|
||||||
|
|
||||||
videosRedundancy: videosRedundancyStats
|
videosRedundancy: videosRedundancyStats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const LAST_MIGRATION_VERSION = 500
|
const LAST_MIGRATION_VERSION = 505
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
26
server/initializers/migrations/0505-user-last-login-date.ts
Normal file
26
server/initializers/migrations/0505-user-last-login-date.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import * as Sequelize from 'sequelize'
|
||||||
|
|
||||||
|
async function up (utils: {
|
||||||
|
transaction: Sequelize.Transaction
|
||||||
|
queryInterface: Sequelize.QueryInterface
|
||||||
|
sequelize: Sequelize.Sequelize
|
||||||
|
}): Promise<void> {
|
||||||
|
|
||||||
|
{
|
||||||
|
const field = {
|
||||||
|
type: Sequelize.DATE,
|
||||||
|
allowNull: true
|
||||||
|
}
|
||||||
|
await utils.queryInterface.addColumn('user', 'lastLoginDate', field)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function down (options) {
|
||||||
|
throw new Error('Not implemented.')
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
up,
|
||||||
|
down
|
||||||
|
}
|
|
@ -180,6 +180,10 @@ async function saveToken (token: TokenInfo, client: OAuthClientModel, user: User
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokenCreated = await OAuthTokenModel.create(tokenToCreate)
|
const tokenCreated = await OAuthTokenModel.create(tokenToCreate)
|
||||||
|
|
||||||
|
user.lastLoginDate = new Date()
|
||||||
|
await user.save()
|
||||||
|
|
||||||
return Object.assign(tokenCreated, { client, user })
|
return Object.assign(tokenCreated, { client, user })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -353,6 +353,11 @@ export class UserModel extends Model<UserModel> {
|
||||||
@Column
|
@Column
|
||||||
pluginAuth: string
|
pluginAuth: string
|
||||||
|
|
||||||
|
@AllowNull(true)
|
||||||
|
@Default(null)
|
||||||
|
@Column
|
||||||
|
lastLoginDate: Date
|
||||||
|
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
|
|
||||||
|
@ -691,10 +696,28 @@ export class UserModel extends Model<UserModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getStats () {
|
static async getStats () {
|
||||||
|
function getActiveUsers (days: number) {
|
||||||
|
const query = {
|
||||||
|
where: {
|
||||||
|
[Op.and]: [
|
||||||
|
literal(`"lastLoginDate" > NOW() - INTERVAL '${days}d'`)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UserModel.count(query)
|
||||||
|
}
|
||||||
|
|
||||||
const totalUsers = await UserModel.count()
|
const totalUsers = await UserModel.count()
|
||||||
|
const totalDailyActiveUsers = await getActiveUsers(1)
|
||||||
|
const totalWeeklyActiveUsers = await getActiveUsers(7)
|
||||||
|
const totalMonthlyActiveUsers = await getActiveUsers(30)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
totalUsers
|
totalUsers,
|
||||||
|
totalDailyActiveUsers,
|
||||||
|
totalWeeklyActiveUsers,
|
||||||
|
totalMonthlyActiveUsers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +831,9 @@ export class UserModel extends Model<UserModel> {
|
||||||
|
|
||||||
createdAt: this.createdAt,
|
createdAt: this.createdAt,
|
||||||
|
|
||||||
pluginAuth: this.pluginAuth
|
pluginAuth: this.pluginAuth,
|
||||||
|
|
||||||
|
lastLoginDate: this.lastLoginDate
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameters.withAdminFlags) {
|
if (parameters.withAdminFlags) {
|
||||||
|
|
|
@ -12,7 +12,8 @@ import {
|
||||||
ServerInfo, unfollow,
|
ServerInfo, unfollow,
|
||||||
uploadVideo,
|
uploadVideo,
|
||||||
viewVideo,
|
viewVideo,
|
||||||
wait
|
wait,
|
||||||
|
userLogin
|
||||||
} from '../../../../shared/extra-utils'
|
} from '../../../../shared/extra-utils'
|
||||||
import { setAccessTokensToServers } from '../../../../shared/extra-utils/index'
|
import { setAccessTokensToServers } from '../../../../shared/extra-utils/index'
|
||||||
import { getStats } from '../../../../shared/extra-utils/server/stats'
|
import { getStats } from '../../../../shared/extra-utils/server/stats'
|
||||||
|
@ -23,6 +24,10 @@ const expect = chai.expect
|
||||||
|
|
||||||
describe('Test stats (excluding redundancy)', function () {
|
describe('Test stats (excluding redundancy)', function () {
|
||||||
let servers: ServerInfo[] = []
|
let servers: ServerInfo[] = []
|
||||||
|
const user = {
|
||||||
|
username: 'user1',
|
||||||
|
password: 'super_password'
|
||||||
|
}
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
this.timeout(60000)
|
this.timeout(60000)
|
||||||
|
@ -31,10 +36,6 @@ describe('Test stats (excluding redundancy)', function () {
|
||||||
|
|
||||||
await doubleFollow(servers[0], servers[1])
|
await doubleFollow(servers[0], servers[1])
|
||||||
|
|
||||||
const user = {
|
|
||||||
username: 'user1',
|
|
||||||
password: 'super_password'
|
|
||||||
}
|
|
||||||
await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
|
await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
|
||||||
|
|
||||||
const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { fixture: 'video_short.webm' })
|
const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { fixture: 'video_short.webm' })
|
||||||
|
@ -96,6 +97,8 @@ describe('Test stats (excluding redundancy)', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should have the correct total videos stats after an unfollow', async function () {
|
it('Should have the correct total videos stats after an unfollow', async function () {
|
||||||
|
this.timeout(15000)
|
||||||
|
|
||||||
await unfollow(servers[2].url, servers[2].accessToken, servers[0])
|
await unfollow(servers[2].url, servers[2].accessToken, servers[0])
|
||||||
await waitJobs(servers)
|
await waitJobs(servers)
|
||||||
|
|
||||||
|
@ -105,6 +108,28 @@ describe('Test stats (excluding redundancy)', function () {
|
||||||
expect(data.totalVideos).to.equal(0)
|
expect(data.totalVideos).to.equal(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should have the correct active users stats', async function () {
|
||||||
|
const server = servers[0]
|
||||||
|
|
||||||
|
{
|
||||||
|
const res = await getStats(server.url)
|
||||||
|
const data: ServerStats = res.body
|
||||||
|
expect(data.totalDailyActiveUsers).to.equal(1)
|
||||||
|
expect(data.totalWeeklyActiveUsers).to.equal(1)
|
||||||
|
expect(data.totalMonthlyActiveUsers).to.equal(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
await userLogin(server, user)
|
||||||
|
|
||||||
|
const res = await getStats(server.url)
|
||||||
|
const data: ServerStats = res.body
|
||||||
|
expect(data.totalDailyActiveUsers).to.equal(2)
|
||||||
|
expect(data.totalWeeklyActiveUsers).to.equal(2)
|
||||||
|
expect(data.totalMonthlyActiveUsers).to.equal(2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
after(async function () {
|
after(async function () {
|
||||||
await cleanupTests(servers)
|
await cleanupTests(servers)
|
||||||
})
|
})
|
||||||
|
|
|
@ -418,6 +418,9 @@ describe('Test users', function () {
|
||||||
expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com')
|
expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com')
|
||||||
expect(user.nsfwPolicy).to.equal('display')
|
expect(user.nsfwPolicy).to.equal('display')
|
||||||
|
|
||||||
|
expect(rootUser.lastLoginDate).to.exist
|
||||||
|
expect(user.lastLoginDate).to.exist
|
||||||
|
|
||||||
userId = user.id
|
userId = user.id
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@ import { VideoRedundancyStrategyWithManual } from '../redundancy'
|
||||||
|
|
||||||
export interface ServerStats {
|
export interface ServerStats {
|
||||||
totalUsers: number
|
totalUsers: number
|
||||||
|
totalDailyActiveUsers: number
|
||||||
|
totalWeeklyActiveUsers: number
|
||||||
|
totalMonthlyActiveUsers: number
|
||||||
|
|
||||||
totalLocalVideos: number
|
totalLocalVideos: number
|
||||||
totalLocalVideoViews: number
|
totalLocalVideoViews: number
|
||||||
totalLocalVideoComments: number
|
totalLocalVideoComments: number
|
||||||
|
|
|
@ -52,6 +52,8 @@ export interface User {
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
|
|
||||||
pluginAuth: string | null
|
pluginAuth: string | null
|
||||||
|
|
||||||
|
lastLoginDate: Date | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MyUserSpecialPlaylist {
|
export interface MyUserSpecialPlaylist {
|
||||||
|
|
Loading…
Add table
Reference in a new issue