mirror of https://github.com/certd/certd
perf: 支持设置用户有效期
parent
82d08e2153
commit
6ac3bc564f
|
@ -16,6 +16,7 @@ export class SysPublicSettings extends BaseSettings {
|
||||||
static __access__ = 'public';
|
static __access__ = 'public';
|
||||||
|
|
||||||
registerEnabled = false;
|
registerEnabled = false;
|
||||||
|
userValidTimeEnabled?:boolean = false;
|
||||||
passwordLoginEnabled = true;
|
passwordLoginEnabled = true;
|
||||||
usernameRegisterEnabled = true;
|
usernameRegisterEnabled = true;
|
||||||
mobileRegisterEnabled = false;
|
mobileRegisterEnabled = false;
|
||||||
|
|
|
@ -15,6 +15,7 @@ import PemInput from "./pem-input.vue";
|
||||||
import { defineAsyncComponent } from "vue";
|
import { defineAsyncComponent } from "vue";
|
||||||
import NotificationSelector from "../views/certd/notification/notification-selector/index.vue";
|
import NotificationSelector from "../views/certd/notification/notification-selector/index.vue";
|
||||||
import EmailSelector from "./email-selector/index.vue";
|
import EmailSelector from "./email-selector/index.vue";
|
||||||
|
import ValidTimeFormat from "./valid-time-format.vue";
|
||||||
export default {
|
export default {
|
||||||
install(app: any) {
|
install(app: any) {
|
||||||
app.component(
|
app.component(
|
||||||
|
@ -27,6 +28,7 @@ export default {
|
||||||
app.component("TextEditable", TextEditable);
|
app.component("TextEditable", TextEditable);
|
||||||
app.component("FileInput", FileInput);
|
app.component("FileInput", FileInput);
|
||||||
app.component("PemInput", PemInput);
|
app.component("PemInput", PemInput);
|
||||||
|
app.component("ValidTimeFormat", ValidTimeFormat);
|
||||||
// app.component("CodeEditor", CodeEditor);
|
// app.component("CodeEditor", CodeEditor);
|
||||||
|
|
||||||
app.component("CronLight", CronLight);
|
app.component("CronLight", CronLight);
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<template>
|
||||||
|
<div class="valid-time-format">
|
||||||
|
<a-tag v-if="isExpired" color="red">{{ prefix || "" }}已过期</a-tag>
|
||||||
|
<a-tag v-if="isValid" color="green" :title="date">
|
||||||
|
<fs-time-humanize v-if="humanize" :model-value="modelValue" :options="{ largest: 1, units: ['y', 'd', 'h'] }" :use-format-greater="30000000000" />
|
||||||
|
<template v-else> {{ prefix || "" }}{{ date }} </template>
|
||||||
|
</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from "vue";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue: number;
|
||||||
|
humanize?: boolean;
|
||||||
|
prefix?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const date = computed(() => {
|
||||||
|
return dayjs(props.modelValue || 0).format("YYYY-MM-DD");
|
||||||
|
});
|
||||||
|
|
||||||
|
const isValid = computed(() => {
|
||||||
|
return props.modelValue > 0 && props.modelValue > new Date().getTime();
|
||||||
|
});
|
||||||
|
|
||||||
|
const isExpired = computed(() => {
|
||||||
|
return props.modelValue > 0 && props.modelValue < new Date().getTime();
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -30,6 +30,7 @@ export type PlusInfo = {
|
||||||
};
|
};
|
||||||
export type SysPublicSetting = {
|
export type SysPublicSetting = {
|
||||||
registerEnabled?: boolean;
|
registerEnabled?: boolean;
|
||||||
|
userValidTimeEnabled?: boolean;
|
||||||
usernameRegisterEnabled?: boolean;
|
usernameRegisterEnabled?: boolean;
|
||||||
mobileRegisterEnabled?: boolean;
|
mobileRegisterEnabled?: boolean;
|
||||||
emailRegisterEnabled?: boolean;
|
emailRegisterEnabled?: boolean;
|
||||||
|
|
|
@ -27,6 +27,8 @@ export interface UserInfoRes {
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
roleIds: number[];
|
roleIds: number[];
|
||||||
isWeak?: boolean;
|
isWeak?: boolean;
|
||||||
|
validTime?: number;
|
||||||
|
status?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoginRes {
|
export interface LoginRes {
|
||||||
|
|
|
@ -35,6 +35,10 @@
|
||||||
<a-divider type="vertical" />
|
<a-divider type="vertical" />
|
||||||
<suite-card class="m-0"></suite-card>
|
<suite-card class="m-0"></suite-card>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="settingsStore.isPlus && settingsStore.sysPublic.userValidTimeEnabled === true && userInfo.validTime">
|
||||||
|
<a-divider type="vertical" />
|
||||||
|
<valid-time-format class="flex-o" prefix="账户有效期:" :model-value="userInfo.validTime" />
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq,
|
||||||
import { useUserStore } from "/@/store/user";
|
import { useUserStore } from "/@/store/user";
|
||||||
import { Modal, notification } from "ant-design-vue";
|
import { Modal, notification } from "ant-design-vue";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import { useSettingStore } from "/@/store/settings";
|
||||||
|
|
||||||
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||||
|
@ -22,6 +23,10 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
const userValidTimeEnabled = compute(() => {
|
||||||
|
return settingStore.sysPublic.userValidTimeEnabled === true;
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
request: {
|
request: {
|
||||||
|
@ -213,20 +218,28 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
||||||
},
|
},
|
||||||
validTime: {
|
validTime: {
|
||||||
title: "有效期",
|
title: "有效期",
|
||||||
type: ["date", "time-humanize"],
|
type: "date",
|
||||||
|
form: {
|
||||||
|
show: userValidTimeEnabled,
|
||||||
|
},
|
||||||
column: {
|
column: {
|
||||||
align: "center",
|
align: "center",
|
||||||
sorter: true,
|
sorter: true,
|
||||||
width: 100,
|
width: 100,
|
||||||
component: {
|
show: userValidTimeEnabled,
|
||||||
title: compute(({ row }) => {
|
cellRender({ value }) {
|
||||||
return dayjs(row.validTime).format("YYYY-MM-DD");
|
if (value == null || value === 0) {
|
||||||
}),
|
return "";
|
||||||
useFormatGreater: 30000000000,
|
}
|
||||||
options: {
|
if (value < dayjs().valueOf()) {
|
||||||
largest: 1,
|
return <a-tag color={"red"}>已过期</a-tag>;
|
||||||
units: ["y", "d", "h"],
|
}
|
||||||
},
|
const date = dayjs(value).format("YYYY-MM-DD");
|
||||||
|
return (
|
||||||
|
<a-tag color={"green"} title={date}>
|
||||||
|
<fs-time-humanize modelValue={value} options={{ largest: 1, units: ["y", "d", "h"] }} useFormatGreater={30000000000} />
|
||||||
|
</a-tag>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
valueBuilder({ value, row, key }) {
|
valueBuilder({ value, row, key }) {
|
||||||
|
|
|
@ -11,6 +11,13 @@
|
||||||
<a-form-item label="开启自助注册" :name="['public', 'registerEnabled']">
|
<a-form-item label="开启自助注册" :name="['public', 'registerEnabled']">
|
||||||
<a-switch v-model:checked="formState.public.registerEnabled" />
|
<a-switch v-model:checked="formState.public.registerEnabled" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="开启用户有效期" :name="['public', 'userValidTimeEnabled']">
|
||||||
|
<div class="flex-o">
|
||||||
|
<a-switch v-model:checked="formState.public.userValidTimeEnabled" :disabled="!settingsStore.isPlus" />
|
||||||
|
<vip-button class="ml-5" mode="button"></vip-button>
|
||||||
|
</div>
|
||||||
|
<div class="helper">有效期内用户可正常使用,失效后流水线将被停用</div>
|
||||||
|
</a-form-item>
|
||||||
<template v-if="formState.public.registerEnabled">
|
<template v-if="formState.public.registerEnabled">
|
||||||
<a-form-item label="开启用户名注册" :name="['public', 'usernameRegisterEnabled']">
|
<a-form-item label="开启用户名注册" :name="['public', 'usernameRegisterEnabled']">
|
||||||
<a-switch v-model:checked="formState.public.usernameRegisterEnabled" />
|
<a-switch v-model:checked="formState.public.usernameRegisterEnabled" />
|
||||||
|
@ -154,6 +161,14 @@ async function loadSysSettings() {
|
||||||
if (data?.private.sms?.type) {
|
if (data?.private.sms?.type) {
|
||||||
await loadTypeDefine(data.private.sms.type);
|
await loadTypeDefine(data.private.sms.type);
|
||||||
}
|
}
|
||||||
|
if (!settingsStore.isPlus) {
|
||||||
|
formState.public.userValidTimeEnabled = false;
|
||||||
|
formState.public.emailRegisterEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!settingsStore.isComm) {
|
||||||
|
formState.public.smsLoginEnabled = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveLoading = ref(false);
|
const saveLoading = ref(false);
|
||||||
|
|
|
@ -329,6 +329,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
if (isComm()) {
|
if (isComm()) {
|
||||||
await this.checkHasDeployCount(id, entity.userId);
|
await this.checkHasDeployCount(id, entity.userId);
|
||||||
}
|
}
|
||||||
|
await this.checkUserStatus(entity.userId)
|
||||||
this.cron.register({
|
this.cron.register({
|
||||||
name: `pipeline.${id}.trigger.once`,
|
name: `pipeline.${id}.trigger.once`,
|
||||||
cron: null,
|
cron: null,
|
||||||
|
@ -446,6 +447,13 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
if (isComm()) {
|
if (isComm()) {
|
||||||
suite = await this.checkHasDeployCount(id, entity.userId);
|
suite = await this.checkHasDeployCount(id, entity.userId);
|
||||||
}
|
}
|
||||||
|
try{
|
||||||
|
await this.checkUserStatus(entity.userId)
|
||||||
|
}catch (e) {
|
||||||
|
logger.info(e.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const pipeline = JSON.parse(entity.content);
|
const pipeline = JSON.parse(entity.content);
|
||||||
if (!pipeline.id) {
|
if (!pipeline.id) {
|
||||||
|
@ -745,5 +753,25 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async checkUserStatus(userId: number) {
|
||||||
|
const userEntity = await this.userService.info(userId);
|
||||||
|
if(userEntity == null){
|
||||||
|
throw new Error('用户不存在');
|
||||||
|
}
|
||||||
|
if(userEntity.status === 0){
|
||||||
|
const message = `账户${userId}已被禁用,禁止运行流水线`
|
||||||
|
throw new Error(message)
|
||||||
|
}
|
||||||
|
const sysPublic = await this.sysSettingsService.getPublicSettings()
|
||||||
|
if(isPlus() && sysPublic.userValidTimeEnabled === true){
|
||||||
|
//校验用户有效期是否设置
|
||||||
|
if(userEntity.validTime!= null && userEntity.validTime > 0){
|
||||||
|
if(userEntity.validTime < new Date().getTime()){
|
||||||
|
//用户已过期
|
||||||
|
const message = `账户${userId}已过有效期,禁止运行流水线`
|
||||||
|
throw new Error(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue