0.4 #5

Merged
m3i46ogeb merged 5 commits from main into develop 3 months ago

@ -77,8 +77,14 @@ const Overview: React.FC = () => {
}
});
/* Get visitors
/* ---------------------------------------------------------------------- */
/* 访visitors
----------------------------------------------------------------------
- `useTinybirdQuery` Tinybird stats 访
- 使 `sanitizeChartData` // range //
- `GhAreaChart` date, value, formattedValue, label
- visitorsChartData 访线
*/
const visitorsParams = {
site_uuid: statsConfig?.id || '',
date_from: formatQueryDate(startDate),
@ -94,7 +100,11 @@ const Overview: React.FC = () => {
});
const visitorsChartData = useMemo(() => {
return sanitizeChartData<WebKpiDataItem>(visitorsData as WebKpiDataItem[] || [], range, 'visits' as keyof WebKpiDataItem, 'sum')?.map((item: WebKpiDataItem) => {
// 先对原始数据进行清洗和聚合(按 range: day/week/month
const sanitized = sanitizeChartData<WebKpiDataItem>(visitorsData as WebKpiDataItem[] || [], range, 'visits' as keyof WebKpiDataItem, 'sum') || [];
// 将每项转换为 GhAreaChart 所需的字段格式
return sanitized.map((item: WebKpiDataItem) => {
const value = Number(item.visits);
const safeValue = isNaN(value) ? 0 : value;
return {

@ -405,7 +405,7 @@ async function addForeign({fromTable, fromColumn, toTable, toColumn, constraintN
* @param {Object} configuration - contains all configuration for this function
* @param {string} configuration.fromTable - name of the table to add the foreign key to
* @param {string} configuration.fromColumn - column of the table to add the foreign key to
* @param {string} configuration.toTable - name of the table to point the foreign key to
* @param {string} configuration.toTable - name of the table to point the foreign key to
* @param {string} configuration.toColumn - column of the table to point the foreign key to
* @param {string} [configuration.constraintName] - name of the FK to delete
* @param {import('knex').Knex} [configuration.transaction] - connection object containing knex reference

@ -77,9 +77,9 @@ User = ghostBookshelf.Model.extend({
format(options) {
if (options.website &&
!validator.isURL(options.website, {
require_protocol: true,
protocols: ['http', 'https']
validator.isURL(options.website, {
require_protocol: true, // 必须包含协议
protocols: ['http', 'https'] // 只允许HTTP和HTTPS协议
})) {
options.website = 'http://' + options.website;
}
@ -96,8 +96,9 @@ User = ghostBookshelf.Model.extend({
},
parse() {
//将数据库存储的URL转换为绝对URL
const attrs = ghostBookshelf.Model.prototype.parse.apply(this, arguments);
//将转换后的URL存储回属性中
['profile_image', 'cover_image'].forEach((attr) => {
if (attrs[attr]) {
attrs[attr] = urlUtils.transformReadyToAbsolute(attrs[attr]);
@ -121,6 +122,7 @@ User = ghostBookshelf.Model.extend({
onDestroying(model, options) {
ghostBookshelf.Model.prototype.onDestroying.apply(this, arguments);
//清除用户角色关联表中的相关记录
return (options.transacting || ghostBookshelf.knex)('roles_users')
.where('user_id', model.id)
.del();
@ -185,7 +187,7 @@ User = ghostBookshelf.Model.extend({
const tasks = [];
let passwordValidation = {};
ghostBookshelf.Model.prototype.onSaving.apply(this, arguments);
ghostBookshelf.Model.prototype.onSaving.apply(this, arguments);// 调用父类的 onSaving 方法
/**
* Bookshelf call order:
@ -194,7 +196,7 @@ User = ghostBookshelf.Model.extend({
*
* Before we can generate a slug, we have to ensure that the name is not blank.
*/
if (!this.get('name')) {
if (!this.get('name')) {// 如果 name 为空,就抛出异常
throw new errors.ValidationError({
message: tpl(messages.valueCannotBeBlank, {
tableName: this.tableName,
@ -205,7 +207,7 @@ User = ghostBookshelf.Model.extend({
// If the user's email is set & has changed & we are not importing
if (self.hasChanged('email') && self.get('email') && !options.importing) {
tasks.push((function lookUpGravatar() {
tasks.push((function lookUpGravatar() {// 如果 email 发生了改变,就去 Gravatar 上查找对应的头像
const {gravatar} = require('../lib/image');
return gravatar.lookup({
@ -218,7 +220,7 @@ User = ghostBookshelf.Model.extend({
})());
}
if (this.hasChanged('slug') || !this.get('slug')) {
if (this.hasChanged('slug') || !this.get('slug')) {// 如果 slug 发生了改变,或者 slug 为空,就生成一个新的 slug
tasks.push((function generateSlug() {
return ghostBookshelf.Model.generateSlug(
User,
@ -256,7 +258,7 @@ User = ghostBookshelf.Model.extend({
return;
}
if (options.importing) {
if (options.importing) {// 如果是导入数据,就不进行密码验证
// always set password to a random uid when importing
this.set('password', security.identifier.uid(50));
@ -264,7 +266,7 @@ User = ghostBookshelf.Model.extend({
if (this.get('status') !== 'inactive') {
this.set('status', 'locked');
}
} else {
} else {// 如果不是导入数据,就进行密码验证
// CASE: we're not importing data, validate the data
passwordValidation = validatePassword(this.get('password'), this.get('email'));
@ -274,7 +276,7 @@ User = ghostBookshelf.Model.extend({
}));
}
}
//密码哈希处理
tasks.push((function hashPassword() {
return security.password.hash(self.get('password'))
.then(function (hash) {
@ -535,7 +537,7 @@ User = ghostBookshelf.Model.extend({
const options = this.filterOptions(unfilteredOptions, 'edit');
const self = this;
const ops = [];
// 检查用户是否只有一个角色
if (data.roles && data.roles.length > 1) {
return Promise.reject(
new errors.ValidationError({
@ -547,6 +549,7 @@ User = ghostBookshelf.Model.extend({
if (data.email) {
ops.push(function checkForDuplicateEmail() {
return self.getByEmail(data.email, options).then(function then(user) {
// 如果查询到有用户使用了相同的邮箱,且该用户不是当前用户,就返回错误
if (user && user.id !== options.id) {
return Promise.reject(new errors.ValidationError({
message: tpl(messages.userUpdateError.emailIsAlreadyInUse)
@ -559,7 +562,7 @@ User = ghostBookshelf.Model.extend({
ops.push(function update() {
return ghostBookshelf.Model.edit.call(self, data, options).then(async (user) => {
let roleId;
//如果没有角色信息就返回用户
if (!data.roles || !data.roles.length) {
return user;
}
@ -571,7 +574,7 @@ User = ghostBookshelf.Model.extend({
if (roles.models[0].id === roleId) {
return;
}
//用户验证逻辑
if (ASSIGNABLE_ROLES.includes(roleId)) {
// return if the role is already assigned
if (roles.models[0].get('name') === roleId) {
@ -595,6 +598,7 @@ User = ghostBookshelf.Model.extend({
);
}
}).then((roleToAssign) => {
// Owner被禁止分配
if (roleToAssign && roleToAssign.get('name') === 'Owner') {
return Promise.reject(
new errors.ValidationError({
@ -602,14 +606,14 @@ User = ghostBookshelf.Model.extend({
})
);
} else if (roleToAssign) {
// assign all other roles
// assign all other roles 更新角色关联
return user.roles().updatePivot({role_id: roleToAssign.id});
}
}).then(() => {
options.status = 'all';
return self.findOne({id: user.id}, options);
return self.findOne({id: user.id}, options);//重新获取完整用户信息
}).then((model) => {
model._changed = user._changed;
model._changed = user._changed;//保留变更标记
return model;
});
});

Loading…
Cancel
Save