mirror of
https://github.com/caprover/caprover
synced 2026-10-08 06:11:34 +00:00
Upgrade EJS and replace Moment
This commit is contained in:
1 parent
715be25792
commit
877ce38015
7 files changed
+171
-86
No files matched your search
Generated
+6
-77
@@ -16,14 +16,13 @@
|
||||
"cron": "^4.3.1",
|
||||
"debug": "~4.4.1",
|
||||
"dockerode": "^5.0.1",
|
||||
"ejs": "^3.1.10",
|
||||
"ejs": "^6.0.1",
|
||||
"express": "^5.1.0",
|
||||
"fs-extra": "^11.3.0",
|
||||
"http-proxy": "^1.18.1",
|
||||
"is-valid-path": "^0.1.1",
|
||||
"js-base64": "^3.7.7",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"moment": "^2.30.1",
|
||||
"morgan": "^1.10.0",
|
||||
"multer": "^2.0.1",
|
||||
"on-finished": "^2.4.1",
|
||||
@@ -3404,12 +3403,6 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/async": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
|
||||
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
@@ -3564,12 +3557,6 @@
|
||||
"@babel/core": "^7.11.0 || ^8.0.0-beta.1 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
@@ -4660,18 +4647,15 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ejs": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
|
||||
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-6.0.1.tgz",
|
||||
"integrity": "sha512-UaaM14yby8U3k02ihS1Bmj5Kz2d7CCQM1scxpgs4Mhkq8F1wR2gl3+Ts4h5Ne4Mnt7M9m4Dw7jsuMr3+xO4vZA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"jake": "^10.8.5"
|
||||
},
|
||||
"bin": {
|
||||
"ejs": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
"node": ">=0.12.18"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
@@ -5220,36 +5204,6 @@
|
||||
"flat-cache": "^6.1.23"
|
||||
}
|
||||
},
|
||||
"node_modules/filelist": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz",
|
||||
"integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"minimatch": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/filelist/node_modules/brace-expansion": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz",
|
||||
"integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/filelist/node_modules/minimatch": {
|
||||
"version": "5.1.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
|
||||
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/filing-cabinet": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/filing-cabinet/-/filing-cabinet-5.5.1.tgz",
|
||||
@@ -6246,23 +6200,6 @@
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jake": {
|
||||
"version": "10.9.4",
|
||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz",
|
||||
"integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"async": "^3.2.6",
|
||||
"filelist": "^1.0.4",
|
||||
"picocolors": "^1.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"jake": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/jest": {
|
||||
"version": "30.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jest/-/jest-30.5.1.tgz",
|
||||
@@ -7353,15 +7290,6 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/morgan": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.12.0.tgz",
|
||||
@@ -7862,6 +7790,7 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
|
||||
+1
-2
@@ -22,14 +22,13 @@
|
||||
"cron": "^4.3.1",
|
||||
"debug": "~4.4.1",
|
||||
"dockerode": "^5.0.1",
|
||||
"ejs": "^3.1.10",
|
||||
"ejs": "^6.0.1",
|
||||
"express": "^5.1.0",
|
||||
"fs-extra": "^11.3.0",
|
||||
"http-proxy": "^1.18.1",
|
||||
"is-valid-path": "^0.1.1",
|
||||
"js-base64": "^3.7.7",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"moment": "^2.30.1",
|
||||
"morgan": "^1.10.0",
|
||||
"multer": "^2.0.1",
|
||||
"on-finished": "^2.4.1",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import SshClientImport = require('ssh2')
|
||||
import { exec } from 'child_process'
|
||||
import * as fs from 'fs-extra'
|
||||
import moment from 'moment'
|
||||
import * as path from 'path'
|
||||
import * as tar from 'tar'
|
||||
import ApiStatusCodes from '../../api/ApiStatusCodes'
|
||||
@@ -12,6 +11,7 @@ import { BackupMeta, RestoringInfo } from '../../models/BackupMeta'
|
||||
import { IHashMapGeneric } from '../../models/ICacheGeneric'
|
||||
import { ServerDockerInfo } from '../../models/ServerDockerInfo'
|
||||
import CaptainConstants from '../../utils/CaptainConstants'
|
||||
import { formatBackupDate } from '../../utils/DateUtils'
|
||||
import Logger from '../../utils/Logger'
|
||||
import Utils from '../../utils/Utils'
|
||||
import Authenticator from '../Authenticator'
|
||||
@@ -738,12 +738,12 @@ export default class BackupManager {
|
||||
// https://github.com/caprover/caprover/issues/1257
|
||||
const hostSegment = hostname ? `-host-${hostname}` : ''
|
||||
|
||||
const now = moment()
|
||||
const now = new Date()
|
||||
const newName = `${
|
||||
CaptainConstants.captainDownloadsDirectory
|
||||
}/${namespace}/caprover-backup-${`${now.format(
|
||||
'YYYY_MM_DD-HH_mm_ss'
|
||||
)}-${now.valueOf()}`}${`-ip-${mainIP}${hostSegment}.tar`}`
|
||||
}/${namespace}/caprover-backup-${`${formatBackupDate(
|
||||
now
|
||||
)}-${now.getTime()}`}${`-ip-${mainIP}${hostSegment}.tar`}`
|
||||
fs.moveSync(tarFilePath, newName)
|
||||
|
||||
setTimeout(
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
const MONTHS = [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December',
|
||||
]
|
||||
|
||||
function pad(value: number, length = 2) {
|
||||
return value.toString().padStart(length, '0')
|
||||
}
|
||||
|
||||
function getOrdinalSuffix(day: number) {
|
||||
if (day >= 11 && day <= 13) {
|
||||
return 'th'
|
||||
}
|
||||
|
||||
switch (day % 10) {
|
||||
case 1:
|
||||
return 'st'
|
||||
case 2:
|
||||
return 'nd'
|
||||
case 3:
|
||||
return 'rd'
|
||||
default:
|
||||
return 'th'
|
||||
}
|
||||
}
|
||||
|
||||
export function formatLogDate(date: Date) {
|
||||
const day = date.getDate()
|
||||
const hours = date.getHours()
|
||||
const twelveHour = hours % 12 || 12
|
||||
const meridiem = hours < 12 ? 'am' : 'pm'
|
||||
|
||||
return `${MONTHS[date.getMonth()]} ${day}${getOrdinalSuffix(
|
||||
day
|
||||
)} ${date.getFullYear()}, ${twelveHour}:${pad(date.getMinutes())}:${pad(
|
||||
date.getSeconds()
|
||||
)}.${pad(date.getMilliseconds(), 3)} ${meridiem} `
|
||||
}
|
||||
|
||||
export function formatBackupDate(date: Date) {
|
||||
return `${date.getFullYear()}_${pad(date.getMonth() + 1)}_${pad(
|
||||
date.getDate()
|
||||
)}-${pad(date.getHours())}_${pad(date.getMinutes())}_${pad(
|
||||
date.getSeconds()
|
||||
)}`
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import moment from 'moment'
|
||||
import { AnyError } from '../models/OtherTypes'
|
||||
import CaptainConstants from './CaptainConstants'
|
||||
import { formatLogDate } from './DateUtils'
|
||||
|
||||
function errorize(error: AnyError) {
|
||||
if (!(error instanceof Error)) {
|
||||
@@ -11,7 +11,7 @@ function errorize(error: AnyError) {
|
||||
}
|
||||
|
||||
function getTime() {
|
||||
return `[36m${moment().format('MMMM Do YYYY, h:mm:ss.SSS a ')}[0m`
|
||||
return `[36m${formatLogDate(new Date())}[0m`
|
||||
}
|
||||
|
||||
class Logger {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { formatBackupDate, formatLogDate } from '../src/utils/DateUtils'
|
||||
|
||||
describe('DateUtils', () => {
|
||||
test.each([
|
||||
[1, 'January 1st 2026, 12:05:04.009 am '],
|
||||
[2, 'January 2nd 2026, 12:05:04.009 am '],
|
||||
[3, 'January 3rd 2026, 12:05:04.009 am '],
|
||||
[11, 'January 11th 2026, 12:05:04.009 am '],
|
||||
[12, 'January 12th 2026, 12:05:04.009 am '],
|
||||
[13, 'January 13th 2026, 12:05:04.009 am '],
|
||||
[21, 'January 21st 2026, 12:05:04.009 am '],
|
||||
])('formats log timestamps for day %i', (day, expected) => {
|
||||
expect(formatLogDate(new Date(2026, 0, day, 0, 5, 4, 9))).toBe(expected)
|
||||
})
|
||||
|
||||
test('formats afternoon log timestamps', () => {
|
||||
expect(formatLogDate(new Date(2026, 8, 7, 19, 5, 4, 9))).toBe(
|
||||
'September 7th 2026, 7:05:04.009 pm '
|
||||
)
|
||||
})
|
||||
|
||||
test('formats backup timestamps', () => {
|
||||
expect(formatBackupDate(new Date(2026, 8, 7, 19, 5, 4, 9))).toBe(
|
||||
'2026_09_07-19_05_04'
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,74 @@
|
||||
import ejs = require('ejs')
|
||||
import fs = require('fs')
|
||||
import path = require('path')
|
||||
|
||||
const templates: [string, Record<string, unknown>][] = [
|
||||
[
|
||||
'base-nginx-conf.ejs',
|
||||
{
|
||||
base: { dhparamsFilePath: '/etc/nginx/dhparam.pem' },
|
||||
},
|
||||
],
|
||||
[
|
||||
'default-page.ejs',
|
||||
{
|
||||
message_title: 'CapRover',
|
||||
message_body: 'Ready',
|
||||
message_link: 'https://caprover.com',
|
||||
message_link_title: 'Documentation',
|
||||
},
|
||||
],
|
||||
[
|
||||
'root-nginx-conf.ejs',
|
||||
{
|
||||
fake: { crtPath: '/fake.crt', keyPath: '/fake.key' },
|
||||
captain: {
|
||||
hasRootSsl: true,
|
||||
crtPath: '/captain.crt',
|
||||
keyPath: '/captain.key',
|
||||
domain: 'captain.example.com',
|
||||
serviceName: 'captain-captain',
|
||||
serviceContainerPort3000: 3000,
|
||||
staticWebRoot: '/captain/static',
|
||||
defaultHtmlDir: '/captain/default',
|
||||
},
|
||||
registry: {
|
||||
hasRootSsl: false,
|
||||
domain: 'registry.example.com',
|
||||
staticWebRoot: '/registry/static',
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
'server-block-conf.ejs',
|
||||
{
|
||||
s: {
|
||||
forceSsl: true,
|
||||
publicDomain: 'app.example.com',
|
||||
staticWebRoot: '/app/static',
|
||||
hasSsl: true,
|
||||
crtPath: '/app.crt',
|
||||
keyPath: '/app.key',
|
||||
logAccessPath: '',
|
||||
gzipOn: false,
|
||||
localDomain: 'srv-captain--app',
|
||||
containerHttpPort: 3000,
|
||||
redirectToPath: '',
|
||||
httpBasicAuthPath: '',
|
||||
websocketSupport: true,
|
||||
customErrorPagesDirectory: '/captain/error-pages',
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
describe('EJS nginx templates', () => {
|
||||
test.each(templates)('renders %s', (filename, data) => {
|
||||
const template = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'template', filename),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
expect(ejs.render(template, data)).toBeTruthy()
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user