mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-07-18 15:24:03 +02:00
Merge branch 'master' into fix-sync
This commit is contained in:
commit
6278267681
25 changed files with 175 additions and 105 deletions
2
.github/ISSUE_TEMPLATE/ask_for_help.yml
vendored
2
.github/ISSUE_TEMPLATE/ask_for_help.yml
vendored
|
@ -3,7 +3,7 @@ name: ❓ Ask for help
|
||||||
description: |
|
description: |
|
||||||
Submit any question related to Uptime Kuma
|
Submit any question related to Uptime Kuma
|
||||||
#title: "[Help]"
|
#title: "[Help]"
|
||||||
labels: ["help", "P3-low"]
|
labels: ["help"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
@ -3,7 +3,7 @@ name: 🐛 Bug Report
|
||||||
description: |
|
description: |
|
||||||
Submit a bug report to help us improve
|
Submit a bug report to help us improve
|
||||||
#title: "[Bug]"
|
#title: "[Bug]"
|
||||||
labels: ["bug", "P2-medium"]
|
labels: ["bug"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
|
@ -3,7 +3,7 @@ name: 🚀 Feature Request
|
||||||
description: |
|
description: |
|
||||||
Submit a proposal for a new feature
|
Submit a proposal for a new feature
|
||||||
# title: "[Feature]"
|
# title: "[Feature]"
|
||||||
labels: ["feature-request", "P3-low"]
|
labels: ["feature-request"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/security_issue.yml
vendored
2
.github/ISSUE_TEMPLATE/security_issue.yml
vendored
|
@ -3,7 +3,7 @@ name: 🛡️ Security Issue
|
||||||
description: |
|
description: |
|
||||||
Notify Louis Lam about a security concern. Please do NOT include any sensitive details in this issue.
|
Notify Louis Lam about a security concern. Please do NOT include any sensitive details in this issue.
|
||||||
# title: "Security Issue"
|
# title: "Security Issue"
|
||||||
labels: ["security", "P1-high"]
|
labels: ["security"]
|
||||||
assignees: [louislam]
|
assignees: [louislam]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
|
|
55
.github/PULL_REQUEST_TEMPLATE.md
vendored
55
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -1,10 +1,10 @@
|
||||||
**⚠️ Please Note: We do not accept all types of pull requests, and we want to ensure we don’t waste your time. Before submitting, make sure you have read our pull request guidelines: [Pull Request Rules](https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md#can-i-create-a-pull-request-for-uptime-kuma)**
|
|
||||||
|
|
||||||
## ❗ Important Announcement
|
## ❗ Important Announcement
|
||||||
|
|
||||||
<details><summary>Click here for more details:</summary>
|
<details><summary>Click here for more details:</summary>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
**⚠️ Please Note: We do not accept all types of pull requests, and we want to ensure we don’t waste your time. Before submitting, make sure you have read our pull request guidelines: [Pull Request Rules](https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md#can-i-create-a-pull-request-for-uptime-kuma)**
|
||||||
|
|
||||||
### 🚧 Temporary Delay in Feature Requests and Pull Request Reviews
|
### 🚧 Temporary Delay in Feature Requests and Pull Request Reviews
|
||||||
|
|
||||||
**At this time, we may be slower to respond to new feature requests and review pull requests. Existing requests and PRs will remain in the backlog but may not be prioritized immediately.**
|
**At this time, we may be slower to respond to new feature requests and review pull requests. Existing requests and PRs will remain in the backlog but may not be prioritized immediately.**
|
||||||
|
@ -26,16 +26,22 @@ We appreciate your patience and understanding as we continue to improve Uptime K
|
||||||
|
|
||||||
## 📋 Overview
|
## 📋 Overview
|
||||||
|
|
||||||
Provide a clear summary of the purpose and scope of this pull request:
|
<!-- Provide a clear summary of the purpose and scope of this pull request:-->
|
||||||
|
|
||||||
- **What problem does this pull request address?**
|
- **What problem does this pull request address?**
|
||||||
|
|
||||||
- Please provide a detailed explanation here.
|
- Please provide a detailed explanation here.
|
||||||
|
|
||||||
- **What features or functionality does this pull request introduce or enhance?**
|
- **What features or functionality does this pull request introduce or enhance?**
|
||||||
|
|
||||||
- Please provide a detailed explanation here.
|
- Please provide a detailed explanation here.
|
||||||
|
|
||||||
|
## 🔗 Related Issues
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Please link any GitHub issues or tasks that this pull request addresses. Use the appropriate issue numbers or links.
|
||||||
|
-->
|
||||||
|
|
||||||
|
- Relates to #issue-number
|
||||||
|
- Resolves #issue-number
|
||||||
|
|
||||||
## 🔄 Changes
|
## 🔄 Changes
|
||||||
|
|
||||||
### 🛠️ Type of change
|
### 🛠️ Type of change
|
||||||
|
@ -52,19 +58,7 @@ Provide a clear summary of the purpose and scope of this pull request:
|
||||||
- [ ] 🔧 Other (please specify):
|
- [ ] 🔧 Other (please specify):
|
||||||
- Provide additional details here.
|
- Provide additional details here.
|
||||||
|
|
||||||
## 🔗 Related Issues
|
## 📄 Checklist
|
||||||
|
|
||||||
<!--
|
|
||||||
Please link any GitHub issues or tasks that this pull request addresses. Use the appropriate issue numbers or links.
|
|
||||||
|
|
||||||
**Note**: Include only issues directly related to this PR. Remove any irrelevant reference.
|
|
||||||
-->
|
|
||||||
|
|
||||||
- Relates to #issue-number
|
|
||||||
- Resolves #issue-number
|
|
||||||
- Fixes #issue-number
|
|
||||||
|
|
||||||
## 📄 Checklist *
|
|
||||||
|
|
||||||
<!-- Please select all options that apply -->
|
<!-- Please select all options that apply -->
|
||||||
|
|
||||||
|
@ -97,26 +91,3 @@ If not, remove this section.
|
||||||
| `DOWN` |  |  |
|
| `DOWN` |  |  |
|
||||||
| Certificate-expiry |  |  |
|
| Certificate-expiry |  |  |
|
||||||
| Testing |  |  |
|
| Testing |  |  |
|
||||||
|
|
||||||
## ℹ️ Additional Context
|
|
||||||
|
|
||||||
Provide any relevant details to assist reviewers in understanding the changes.
|
|
||||||
|
|
||||||
<details><summary>Click here for more details:</summary>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
**Key Considerations**:
|
|
||||||
|
|
||||||
- **Design decisions** – Key choices or trade-offs made during development.
|
|
||||||
- **Alternative solutions** – Approaches considered but not implemented, along with reasons.
|
|
||||||
- **Relevant links** – Specifications, discussions, or resources that provide context.
|
|
||||||
- **Dependencies** – Related pull requests or issues that must be resolved before merging.
|
|
||||||
- **Additional context** – Any other details that may help reviewers understand the changes.
|
|
||||||
|
|
||||||
Provide details here
|
|
||||||
|
|
||||||
## 💬 Requested Feedback
|
|
||||||
|
|
||||||
<!-- If a part of our docs is unclear, you are unsure how to do something/.. this is where we would appreciate your feedback -->
|
|
||||||
|
|
||||||
- `Mention documents needing feedback here`
|
|
||||||
|
|
|
@ -79,6 +79,10 @@ USER node
|
||||||
RUN git config --global user.email "no-reply@no-reply.com"
|
RUN git config --global user.email "no-reply@no-reply.com"
|
||||||
RUN git config --global user.name "PR Tester"
|
RUN git config --global user.name "PR Tester"
|
||||||
RUN git clone https://github.com/louislam/uptime-kuma.git .
|
RUN git clone https://github.com/louislam/uptime-kuma.git .
|
||||||
|
|
||||||
|
# Hide the warning when running in detached head state
|
||||||
|
RUN git config --global advice.detachedHead false
|
||||||
|
|
||||||
RUN npm ci
|
RUN npm ci
|
||||||
|
|
||||||
EXPOSE 3000 3001
|
EXPOSE 3000 3001
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
const childProcess = require("child_process");
|
|
||||||
|
|
||||||
if (!process.env.UPTIME_KUMA_GH_REPO) {
|
|
||||||
console.error("Please set a repo to the environment variable 'UPTIME_KUMA_GH_REPO' (e.g. mhkarimi1383:goalert-notification)");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let inputArray = process.env.UPTIME_KUMA_GH_REPO.split(":");
|
|
||||||
|
|
||||||
if (inputArray.length !== 2) {
|
|
||||||
console.error("Invalid format. Please set a repo to the environment variable 'UPTIME_KUMA_GH_REPO' (e.g. mhkarimi1383:goalert-notification)");
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = inputArray[0];
|
|
||||||
let branch = inputArray[1];
|
|
||||||
|
|
||||||
console.log("Checkout pr");
|
|
||||||
|
|
||||||
// Checkout the pr
|
|
||||||
let result = childProcess.spawnSync("git", [ "remote", "add", name, `https://github.com/${name}/uptime-kuma` ]);
|
|
||||||
|
|
||||||
console.log(result.stdout.toString());
|
|
||||||
console.error(result.stderr.toString());
|
|
||||||
|
|
||||||
result = childProcess.spawnSync("git", [ "fetch", name, branch ]);
|
|
||||||
|
|
||||||
console.log(result.stdout.toString());
|
|
||||||
console.error(result.stderr.toString());
|
|
||||||
|
|
||||||
result = childProcess.spawnSync("git", [ "checkout", `${name}/${branch}`, "--force" ]);
|
|
||||||
|
|
||||||
console.log(result.stdout.toString());
|
|
||||||
console.error(result.stderr.toString());
|
|
34
extra/checkout-pr.mjs
Normal file
34
extra/checkout-pr.mjs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import childProcess from "child_process";
|
||||||
|
import { parsePrName } from "./kuma-pr/pr-lib.mjs";
|
||||||
|
|
||||||
|
let { name, branch } = parsePrName(process.env.UPTIME_KUMA_GH_REPO);
|
||||||
|
|
||||||
|
console.log(`Checking out PR from ${name}:${branch}`);
|
||||||
|
|
||||||
|
// Checkout the pr
|
||||||
|
let result = childProcess.spawnSync("git", [ "remote", "add", name, `https://github.com/${name}/uptime-kuma` ], {
|
||||||
|
stdio: "inherit"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.status !== 0) {
|
||||||
|
console.error("Failed to add remote repository.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = childProcess.spawnSync("git", [ "fetch", name, branch ], {
|
||||||
|
stdio: "inherit"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.status !== 0) {
|
||||||
|
console.error("Failed to fetch the branch.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = childProcess.spawnSync("git", [ "checkout", `${name}/${branch}`, "--force" ], {
|
||||||
|
stdio: "inherit"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.status !== 0) {
|
||||||
|
console.error("Failed to checkout the branch.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
26
extra/kuma-pr/index.mjs
Normal file
26
extra/kuma-pr/index.mjs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
import { spawn } from "child_process";
|
||||||
|
import { parsePrName } from "./pr-lib.mjs";
|
||||||
|
|
||||||
|
const prName = process.argv[2];
|
||||||
|
|
||||||
|
// Pre-check the prName here, so testers don't need to wait until the Docker image is pulled to see the error.
|
||||||
|
try {
|
||||||
|
parsePrName(prName);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
spawn("docker", [
|
||||||
|
"run",
|
||||||
|
"--rm",
|
||||||
|
"-it",
|
||||||
|
"-p", "3000:3000",
|
||||||
|
"-p", "3001:3001",
|
||||||
|
"--pull", "always",
|
||||||
|
"-e", `UPTIME_KUMA_GH_REPO=${prName}`,
|
||||||
|
"louislam/uptime-kuma:pr-test2"
|
||||||
|
], {
|
||||||
|
stdio: "inherit",
|
||||||
|
});
|
8
extra/kuma-pr/package.json
Normal file
8
extra/kuma-pr/package.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"name": "kuma-pr",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"bin": {
|
||||||
|
"kuma-pr": "./index.mjs"
|
||||||
|
}
|
||||||
|
}
|
39
extra/kuma-pr/pr-lib.mjs
Normal file
39
extra/kuma-pr/pr-lib.mjs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* Parse <name>:<branch> to an object.
|
||||||
|
* @param {string} prName <name>:<branch>
|
||||||
|
* @returns {object} An object with name and branch properties.
|
||||||
|
*/
|
||||||
|
export function parsePrName(prName) {
|
||||||
|
let name = "louislam";
|
||||||
|
let branch;
|
||||||
|
|
||||||
|
const errorMessage = "Please set a repo to the environment variable 'UPTIME_KUMA_GH_REPO' (e.g. mhkarimi1383:goalert-notification)";
|
||||||
|
|
||||||
|
if (!prName) {
|
||||||
|
throw new Error(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
prName = prName.trim();
|
||||||
|
if (prName === "") {
|
||||||
|
throw new Error(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputArray = prName.split(":");
|
||||||
|
|
||||||
|
// Just realized that owner's prs are not prefixed with "louislam:"
|
||||||
|
if (inputArray.length === 1) {
|
||||||
|
branch = inputArray[0];
|
||||||
|
|
||||||
|
} else if (inputArray.length === 2) {
|
||||||
|
name = inputArray[0];
|
||||||
|
branch = inputArray[1];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error("Invalid format. The format is like this: mhkarimi1383:goalert-notification");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
branch
|
||||||
|
};
|
||||||
|
}
|
|
@ -57,7 +57,7 @@
|
||||||
"release-nightly": "node ./extra/release/nightly.mjs",
|
"release-nightly": "node ./extra/release/nightly.mjs",
|
||||||
"git-remove-tag": "git tag -d",
|
"git-remove-tag": "git tag -d",
|
||||||
"build-dist-and-restart": "npm run build && npm run start-server-dev",
|
"build-dist-and-restart": "npm run build && npm run start-server-dev",
|
||||||
"start-pr-test": "node extra/checkout-pr.js && npm install && npm run dev",
|
"start-pr-test": "node extra/checkout-pr.mjs && npm install && npm run dev",
|
||||||
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go",
|
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go",
|
||||||
"deploy-demo-server": "node extra/deploy-demo-server.js",
|
"deploy-demo-server": "node extra/deploy-demo-server.js",
|
||||||
"sort-contributors": "node extra/sort-contributors.js",
|
"sort-contributors": "node extra/sort-contributors.js",
|
||||||
|
|
|
@ -26,7 +26,7 @@ exports.login = async function (username, password) {
|
||||||
// Upgrade the hash to bcrypt
|
// Upgrade the hash to bcrypt
|
||||||
if (passwordHash.needRehash(user.password)) {
|
if (passwordHash.needRehash(user.password)) {
|
||||||
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
|
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
|
||||||
passwordHash.generate(password),
|
await passwordHash.generate(password),
|
||||||
user.id,
|
user.id,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
const fsAsync = fs.promises;
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const { setSetting, setting } = require("./util-server");
|
const { setSetting, setting } = require("./util-server");
|
||||||
const { log, sleep } = require("../src/util");
|
const { log, sleep } = require("../src/util");
|
||||||
|
@ -707,12 +708,12 @@ class Database {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the size of the database (SQLite only)
|
* Get the size of the database (SQLite only)
|
||||||
* @returns {number} Size of database
|
* @returns {Promise<number>} Size of database
|
||||||
*/
|
*/
|
||||||
static getSize() {
|
static async getSize() {
|
||||||
if (Database.dbConfig.type === "sqlite") {
|
if (Database.dbConfig.type === "sqlite") {
|
||||||
log.debug("db", "Database.getSize()");
|
log.debug("db", "Database.getSize()");
|
||||||
let stats = fs.statSync(Database.sqlitePath);
|
let stats = await fsAsync.stat(Database.sqlitePath);
|
||||||
log.debug("db", stats);
|
log.debug("db", stats);
|
||||||
return stats.size;
|
return stats.size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ class User extends BeanModel {
|
||||||
*/
|
*/
|
||||||
static async resetPassword(userID, newPassword) {
|
static async resetPassword(userID, newPassword) {
|
||||||
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
|
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
|
||||||
passwordHash.generate(newPassword),
|
await passwordHash.generate(newPassword),
|
||||||
userID
|
userID
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ class User extends BeanModel {
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async resetPassword(newPassword) {
|
async resetPassword(newPassword) {
|
||||||
const hashedPassword = passwordHash.generate(newPassword);
|
const hashedPassword = await passwordHash.generate(newPassword);
|
||||||
|
|
||||||
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
|
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
|
||||||
hashedPassword,
|
hashedPassword,
|
||||||
|
|
|
@ -5,10 +5,10 @@ const saltRounds = 10;
|
||||||
/**
|
/**
|
||||||
* Hash a password
|
* Hash a password
|
||||||
* @param {string} password Password to hash
|
* @param {string} password Password to hash
|
||||||
* @returns {string} Hash
|
* @returns {Promise<string>} Hash
|
||||||
*/
|
*/
|
||||||
exports.generate = function (password) {
|
exports.generate = function (password) {
|
||||||
return bcrypt.hashSync(password, saltRounds);
|
return bcrypt.hash(password, saltRounds);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -674,7 +674,7 @@ let needSetup = false;
|
||||||
|
|
||||||
let user = R.dispense("user");
|
let user = R.dispense("user");
|
||||||
user.username = username;
|
user.username = username;
|
||||||
user.password = passwordHash.generate(password);
|
user.password = await passwordHash.generate(password);
|
||||||
await R.store(user);
|
await R.store(user);
|
||||||
|
|
||||||
needSetup = false;
|
needSetup = false;
|
||||||
|
|
|
@ -20,7 +20,7 @@ module.exports.apiKeySocketHandler = (socket) => {
|
||||||
checkLogin(socket);
|
checkLogin(socket);
|
||||||
|
|
||||||
let clearKey = nanoid(40);
|
let clearKey = nanoid(40);
|
||||||
let hashedKey = passwordHash.generate(clearKey);
|
let hashedKey = await passwordHash.generate(clearKey);
|
||||||
key["key"] = hashedKey;
|
key["key"] = hashedKey;
|
||||||
let bean = await APIKey.save(key, socket.userID);
|
let bean = await APIKey.save(key, socket.userID);
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ module.exports.databaseSocketHandler = (socket) => {
|
||||||
checkLogin(socket);
|
checkLogin(socket);
|
||||||
callback({
|
callback({
|
||||||
ok: true,
|
ok: true,
|
||||||
size: Database.getSize(),
|
size: await Database.getSize(),
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
callback({
|
callback({
|
||||||
|
|
|
@ -4,7 +4,7 @@ const { sendInfo } = require("../client");
|
||||||
const { checkLogin } = require("../util-server");
|
const { checkLogin } = require("../util-server");
|
||||||
const GameResolver = require("gamedig/lib/GameResolver");
|
const GameResolver = require("gamedig/lib/GameResolver");
|
||||||
const { testChrome } = require("../monitor-types/real-browser-monitor-type");
|
const { testChrome } = require("../monitor-types/real-browser-monitor-type");
|
||||||
const fs = require("fs");
|
const fsAsync = require("fs").promises;
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
let gameResolver = new GameResolver();
|
let gameResolver = new GameResolver();
|
||||||
|
@ -90,7 +90,7 @@ module.exports.generalSocketHandler = (socket, server) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("getPushExample", (language, callback) => {
|
socket.on("getPushExample", async (language, callback) => {
|
||||||
try {
|
try {
|
||||||
checkLogin(socket);
|
checkLogin(socket);
|
||||||
if (!/^[a-z-]+$/.test(language)) {
|
if (!/^[a-z-]+$/.test(language)) {
|
||||||
|
@ -106,13 +106,13 @@ module.exports.generalSocketHandler = (socket, server) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let dir = path.join("./extra/push-examples", language);
|
let dir = path.join("./extra/push-examples", language);
|
||||||
let files = fs.readdirSync(dir);
|
let files = await fsAsync.readdir(dir);
|
||||||
|
|
||||||
for (let file of files) {
|
for (let file of files) {
|
||||||
if (file.startsWith("index.")) {
|
if (file.startsWith("index.")) {
|
||||||
callback({
|
callback({
|
||||||
ok: true,
|
ok: true,
|
||||||
code: fs.readFileSync(path.join(dir, file), "utf8"),
|
code: await fsAsync.readFile(path.join(dir, file), "utf8"),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ exports.initJWTSecret = async () => {
|
||||||
jwtSecretBean.key = "jwtSecret";
|
jwtSecretBean.key = "jwtSecret";
|
||||||
}
|
}
|
||||||
|
|
||||||
jwtSecretBean.value = passwordHash.generate(genSecret());
|
jwtSecretBean.value = await passwordHash.generate(genSecret());
|
||||||
await R.store(jwtSecretBean);
|
await R.store(jwtSecretBean);
|
||||||
return jwtSecretBean;
|
return jwtSecretBean;
|
||||||
};
|
};
|
||||||
|
|
19
src/i18n.js
19
src/i18n.js
|
@ -75,11 +75,20 @@ export function currentLocale() {
|
||||||
if (locale in messages) {
|
if (locale in messages) {
|
||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
// some locales are further specified such as "en-US".
|
// If the locale is a 2-letter code, we can try to find a regional variant
|
||||||
// If we only have a generic locale for this, we can use it too
|
// e.g. "fr" may not be in the messages, but "fr-FR" is
|
||||||
const genericLocale = locale.split("-")[0];
|
if (locale.length === 2) {
|
||||||
if (genericLocale in messages) {
|
const regionalLocale = `${locale}-${locale.toUpperCase()}`;
|
||||||
return genericLocale;
|
if (regionalLocale in messages) {
|
||||||
|
return regionalLocale;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Some locales are further specified such as "en-US".
|
||||||
|
// If we only have a generic locale for this, we can use it too
|
||||||
|
const genericLocale = locale.slice(0, 2);
|
||||||
|
if (genericLocale in messages) {
|
||||||
|
return genericLocale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "en";
|
return "en";
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<span class="fs-4 title">{{ $t("Uptime Kuma") }}</span>
|
<span class="fs-4 title">{{ $t("Uptime Kuma") }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<a v-if="hasNewVersion" target="_blank" href="https://github.com/louislam/uptime-kuma/releases" class="btn btn-info me-3">
|
<a v-if="hasNewVersion" target="_blank" href="https://github.com/louislam/uptime-kuma/releases" class="btn btn-primary me-3">
|
||||||
<font-awesome-icon icon="arrow-alt-circle-up" /> {{ $t("New Update") }}
|
<font-awesome-icon icon="arrow-alt-circle-up" /> {{ $t("New Update") }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
<div>{{ monitor.id }}</div>
|
<div>{{ monitor.id }}</div>
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
</h1>
|
||||||
<p v-if="monitor.description">{{ monitor.description }}</p>
|
<!-- eslint-disable-next-line vue/no-v-html-->
|
||||||
|
<p v-if="monitor.description" v-html="descriptionHTML"></p>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="tags">
|
<div class="tags">
|
||||||
<Tag v-for="tag in monitor.tags" :key="tag.id" :item="tag" :size="'sm'" />
|
<Tag v-for="tag in monitor.tags" :key="tag.id" :item="tag" :size="'sm'" />
|
||||||
|
@ -285,6 +286,8 @@ import Tag from "../components/Tag.vue";
|
||||||
import CertificateInfo from "../components/CertificateInfo.vue";
|
import CertificateInfo from "../components/CertificateInfo.vue";
|
||||||
import { getMonitorRelativeURL } from "../util.ts";
|
import { getMonitorRelativeURL } from "../util.ts";
|
||||||
import { URL } from "whatwg-url";
|
import { URL } from "whatwg-url";
|
||||||
|
import DOMPurify from "dompurify";
|
||||||
|
import { marked } from "marked";
|
||||||
import { getResBaseURL } from "../util-frontend";
|
import { getResBaseURL } from "../util-frontend";
|
||||||
import { highlight, languages } from "prismjs/components/prism-core";
|
import { highlight, languages } from "prismjs/components/prism-core";
|
||||||
import "prismjs/components/prism-clike";
|
import "prismjs/components/prism-clike";
|
||||||
|
@ -399,6 +402,14 @@ export default {
|
||||||
|
|
||||||
screenshotURL() {
|
screenshotURL() {
|
||||||
return getResBaseURL() + this.monitor.screenshot + "?time=" + this.cacheTime;
|
return getResBaseURL() + this.monitor.screenshot + "?time=" + this.cacheTime;
|
||||||
|
},
|
||||||
|
|
||||||
|
descriptionHTML() {
|
||||||
|
if (this.monitor.description != null) {
|
||||||
|
return DOMPurify.sanitize(marked(this.monitor.description));
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -157,12 +157,12 @@
|
||||||
<!-- Admin functions -->
|
<!-- Admin functions -->
|
||||||
<div v-if="hasToken" class="mb-4">
|
<div v-if="hasToken" class="mb-4">
|
||||||
<div v-if="!enableEditMode">
|
<div v-if="!enableEditMode">
|
||||||
<button class="btn btn-info me-2" data-testid="edit-button" @click="edit">
|
<button class="btn btn-primary me-2" data-testid="edit-button" @click="edit">
|
||||||
<font-awesome-icon icon="edit" />
|
<font-awesome-icon icon="edit" />
|
||||||
{{ $t("Edit Status Page") }}
|
{{ $t("Edit Status Page") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<a href="/manage-status-page" class="btn btn-info">
|
<a href="/manage-status-page" class="btn btn-primary">
|
||||||
<font-awesome-icon icon="tachometer-alt" />
|
<font-awesome-icon icon="tachometer-alt" />
|
||||||
{{ $t("Go to Dashboard") }}
|
{{ $t("Go to Dashboard") }}
|
||||||
</a>
|
</a>
|
||||||
|
|
Loading…
Add table
Reference in a new issue