增加消息通道独立推送

This commit is contained in:
xpnas 2021-04-05 17:06:21 +08:00
parent fa1ad54afb
commit ec70089d77
12 changed files with 121 additions and 61 deletions

View File

@ -3,8 +3,8 @@
<el-dialog :title='title' :visible.sync='dialogVisible' :append-to-body='true'> <el-dialog :title='title' :visible.sync='dialogVisible' :append-to-body='true'>
<el-form ref="authform" :model="authform" label-width="120px" label-position='right' :rules="authformrules"> <el-form ref="authform" :model="authform" label-width="120px" label-position='right' :rules="authformrules">
<el-form-item label='通道类型'> <el-form-item label='通道类型'>
<el-select :disabled='isModify' value-key="key" v-model='selectTemplate' placeholder='请选择' @change="selectTemplateChange"> <el-select :disabled='isModify' value-key="type" v-model='selectTemplate' placeholder='请选择' @change="selectTemplateChange">
<el-option v-for="item in sendTemplates" :key="item.key" :label="item.name" :value="item"> <el-option v-for="item in sendTemplates" :key="item.type" :label="item.typeName" :value="item">
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -14,6 +14,12 @@
<el-form-item v-for="(item) in selectTemplate.values" :label="item.description" :key="item.name" required> <el-form-item v-for="(item) in selectTemplate.values" :label="item.description" :key="item.name" required>
<el-input v-model="item.value" :placeholder="item.default" :readonly="item.readonly"></el-input> <el-input v-model="item.value" :placeholder="item.default" :readonly="item.readonly"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="绑定地址" v-show="isBark">
<el-input v-model="selectTemplate.barkUrl" readonly></el-input>
</el-form-item>
<el-form-item label="二维码地址" v-show="isBark">
<div id="bark"></div>
</el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
@ -32,7 +38,7 @@
</el-table-column> </el-table-column>
<el-table-column label='类型' width='110' align='center'> <el-table-column label='类型' width='110' align='center'>
<template slot-scope='scope'> <template slot-scope='scope'>
<span>{{ scope.row.type }}</span> <span>{{ scope.row.typeName }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label='名称' width='110' align='center'> <el-table-column label='名称' width='110' align='center'>
@ -40,9 +46,9 @@
<span>{{ scope.row.name }}</span> <span>{{ scope.row.name }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label='配置信息' align='center'>> <el-table-column label='调用接口' align='center'>
<template slot-scope='scope'> <template slot-scope='scope'>
{{ scope.row.authData }} <el-link type="primary" target="_blank"> <a :href="scope.row.url" target="_blank" class="buttonText">{{scope.row.url}}</a></el-link>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align='center' prop='created_at' label='编辑' width='200'> <el-table-column align='center' prop='created_at' label='编辑' width='200'>
@ -103,7 +109,8 @@ export default {
isModify: false, isModify: false,
authform: {}, authform: {},
title: "设置", title: "设置",
sendKey: "" sendKey: "",
isBark: false
} }
}, },
created() { created() {
@ -114,6 +121,10 @@ export default {
this.listLoading = true this.listLoading = true
getSendAuths().then((response) => { getSendAuths().then((response) => {
this.sendAuthinfos = response.data this.sendAuthinfos = response.data
let origin = window.document.location.origin;
for (var sendinfo of this.sendAuthinfos) {
sendinfo.url = origin + '/' + sendinfo.key + ".send/{title}/{data}"
}
this.listLoading = false this.listLoading = false
}) })
getSendTemplates().then((response) => { getSendTemplates().then((response) => {
@ -129,11 +140,24 @@ export default {
}, },
selectTemplateChange(selectTemplate) { selectTemplateChange(selectTemplate) {
this.selectTemplate = deepClone(selectTemplate) this.selectTemplate = deepClone(selectTemplate)
this.isBark = false;
if (this.selectTemplate.warning) { if (this.selectTemplate.warning) {
this.$message({ this.$message({
message: this.selectTemplate.warning, message: this.selectTemplate.warning,
type: 'warning' type: 'warning'
}) })
if (this.selectTemplate.typeName == 'Bark') {
this.isBark = true;
this.selectTemplate.values = [];
let origin = window.document.location.origin;
this.selectTemplate.barkUrl = origin + '?act=' + this.sendKey;
document.getElementById("bark").innerHTML = '';
new QRCode(document.getElementById('bark'), {
text: this.selectTemplate.barkUrl,
width: 250,
height: 250,
});
}
} }
}, },
submitForm(formName) { submitForm(formName) {
@ -181,6 +205,7 @@ export default {
}); });
}, },
addAuth() { addAuth() {
this.isBark = false;
this.title = '新增设置' this.title = '新增设置'
this.dialogVisible = true this.dialogVisible = true
this.isModify = false this.isModify = false
@ -190,21 +215,18 @@ export default {
modifyAuth(index, row) { modifyAuth(index, row) {
this.title = '修改设置' this.title = '修改设置'
this.isModify = true; this.isModify = true;
this.isBark = false;
this.selectTemplate = deepClone(row); this.selectTemplate = deepClone(row);
if (this.selectTemplate.type == "Bark") { if (this.selectTemplate.typeName == "Bark") {
let wPath = window.document.location.href; this.isBark = true;
let pathName = this.$route.path; let origin = window.document.location.origin;
let pos = wPath.indexOf(pathName);
let localhostPath = wPath.substring(0, pos);
localhostPath = localhostPath.replace("#", "");
var devieItem = this.selectTemplate.values.find(item => { var devieItem = this.selectTemplate.values.find(item => {
return item.name == "DeviceKey" return item.name == "DeviceKey"
}) })
var sendUrlItem = this.selectTemplate.values.find(item => { var sendUrlItem = this.selectTemplate.values.find(item => {
return item.name == "SendUrl" return item.name == "SendUrl"
}); });
sendUrlItem.value = localhostPath + "?act=" + this.sendKey + "/" + devieItem.value + "/{title}/{data}" sendUrlItem.value = origin + "?act=" + this.sendKey + "/" + devieItem.value + "/{title}/{data}"
} }
this.dialogVisible = true; this.dialogVisible = true;
@ -234,6 +256,9 @@ export default {
this.$message.error(state ? '激活失败' : '注销失败'); this.$message.error(state ? '激活失败' : '注销失败');
} }
}) })
},
getBarkUrl() {
} }
} }
} }

View File

@ -20,17 +20,17 @@
<el-divider content-position="left">重置授权</el-divider> <el-divider content-position="left">重置授权</el-divider>
<el-form ref="resetform" :model="keyForm" label-width="20%"> <el-form ref="resetform" :model="keyForm" label-width="20%">
<el-form-item label="当前SendKey"> <el-form-item label="当前Token">
<el-input v-model="keyForm.sendKey" :readonly="true"></el-input> <el-input v-model="keyForm.sendKey" :readonly="true"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="快捷地址(标题)"> <el-form-item label="调用接口(标题)">
<el-input type="textarea" v-model="keyForm.sendUrlTitle" :readonly="true"></el-input> <el-input type="textarea" v-model="keyForm.sendUrlTitle" :readonly="true"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="快捷地址(完整)"> <el-form-item label="调用接口(完整)">
<el-input type="textarea" v-model="keyForm.sendUrl" :readonly="true"></el-input> <el-input type="textarea" v-model="keyForm.sendUrl" :readonly="true"></el-input>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="onReSendKey('resetform')">重置SendKey</el-button> <el-button type="primary" @click="onReSendKey('resetform')">重置Token</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -100,14 +100,10 @@ export default {
getSendKey().then((response) => { getSendKey().then((response) => {
this.keyForm.sendKey = response.data; this.keyForm.sendKey = response.data;
this.messageForm.sendKey = response.data; this.messageForm.sendKey = response.data;
let wPath = window.document.location.href; let origin = window.document.location.origin;
let pathName = this.$route.path; this.keyForm.sendUrlTitle = origin + '/' + this.keyForm.sendKey + '.send' + "/{title}"
let pos = wPath.indexOf(pathName); this.keyForm.sendUrl = origin + '/' + this.keyForm.sendKey + '.send' + "/{title}/{data}"
let localhostPath = wPath.substring(0, pos); this.keyForm.barkUrl = origin + '?act=' + this.keyForm.sendKey
localhostPath = localhostPath.replace("#", "");
this.keyForm.sendUrlTitle = localhostPath + this.keyForm.sendKey + '.send' + "/{title}"
this.keyForm.sendUrl = localhostPath + this.keyForm.sendKey + '.send' + "/{title}/{data}"
this.keyForm.barkUrl = wPath.substring(0, pos - 2) + '?act=' + this.keyForm.sendKey
this.listLoading = false; this.listLoading = false;
new QRCode(document.getElementById("qrcode"), { new QRCode(document.getElementById("qrcode"), {
text: this.keyForm.barkUrl, text: this.keyForm.barkUrl,

View File

@ -90,7 +90,7 @@ Register(device_key) : Register(act, key, devicetoken);
if (barkSendAuthInfo == null) if (barkSendAuthInfo == null)
{ {
device_key = 16.GenerateCheckCode(); device_key = Guid.NewGuid().ToString("N").ToUpper();
barkAuth = new BarkAuth() { DeviceKey = device_key, DeviceToken = device_token, IsArchive = "1", AutoMaticallyCopy = "1", Sound = "1107" }; barkAuth = new BarkAuth() { DeviceKey = device_key, DeviceToken = device_token, IsArchive = "1", AutoMaticallyCopy = "1", Sound = "1107" };
barkSendAuthInfo = new SendAuthInfo() barkSendAuthInfo = new SendAuthInfo()
{ {

View File

@ -19,21 +19,6 @@ namespace Inotify.Controllers
return Fail(400, "you have no tunnel is acitve"); return Fail(400, "you have no tunnel is acitve");
} }
if (!string.IsNullOrEmpty(key))
{
if (DBManager.Instance.IsSendKey(key, out bool isActive))
{
if (!isActive)
{
return Fail(400, $"device:{key} tunnel is not acitve");
}
}
else
{
return Fail(400, $"device:{key} is not registered");
}
}
var message = new SendMessage() var message = new SendMessage()
{ {
Token = token, Token = token,
@ -47,6 +32,34 @@ namespace Inotify.Controllers
return OK(); return OK();
} }
} }
else
{
key = token;
if (DBManager.Instance.IsSendKey(token, out bool isActive, out token))
{
if (!isActive)
{
return Fail(400, $"device:{key} tunnel is not acitve");
}
var message = new SendMessage()
{
Token = token,
Title = title,
Data = data,
Key = key,
};
if (SendTaskManager.Instance.SendMessage(message))
{
return OK();
}
}
else
{
return Fail(400, $"device:{key} is not registered");
}
}
return Fail(400, $"token:{token} is not registered"); return Fail(400, $"token:{token} is not registered");
} }

View File

@ -41,14 +41,16 @@ namespace Inotify.Controllers
var sendTemplate = SendTaskManager.Instance.GetInputTemplate(sendAuthInfo.SendMethodTemplate); var sendTemplate = SendTaskManager.Instance.GetInputTemplate(sendAuthInfo.SendMethodTemplate);
if (sendTemplate != null) if (sendTemplate != null)
{ {
sendTemplate.Key = sendAuthInfo.Key;
sendTemplate.SendAuthId = sendAuthInfo.Id;
sendTemplate.Name = sendAuthInfo.Name; sendTemplate.Name = sendAuthInfo.Name;
sendTemplate.AuthData = sendAuthInfo.AuthData; sendTemplate.AuthData = sendAuthInfo.AuthData;
sendTemplate.SendAuthId = sendAuthInfo.Id;
sendTemplate.IsActive = sendAuthInfo.Active; sendTemplate.IsActive = sendAuthInfo.Active;
sendTemplate.AuthToTemplate(sendAuthInfo.AuthData); sendTemplate.AuthToTemplate(sendAuthInfo.AuthData);
userSendTemplates.Add(sendTemplate); userSendTemplates.Add(sendTemplate);
} }
if (barkTemplateAttribute.Key == sendTemplate.Key) if (barkTemplateAttribute.Key == sendTemplate.Type)
{ {
sendTemplate.Values.FirstOrDefault(e => e.Name == nameof(BarkSendTemplate.Auth.SendUrl)).Value = ""; sendTemplate.Values.FirstOrDefault(e => e.Name == nameof(BarkSendTemplate.Auth.SendUrl)).Value = "";
} }
@ -96,10 +98,10 @@ namespace Inotify.Controllers
public JsonResult AddSendAuth(InputTemeplate inputTemeplate) public JsonResult AddSendAuth(InputTemeplate inputTemeplate)
{ {
var userInfo = DBManager.Instance.GetUser(UserName); var userInfo = DBManager.Instance.GetUser(UserName);
if (userInfo != null && inputTemeplate.Key != null && inputTemeplate.Name != null) if (userInfo != null && inputTemeplate.Type != null && inputTemeplate.Name != null)
{ {
var barkKey = typeof(BarkSendTemplate).GetCustomAttributes(typeof(SendMethodKeyAttribute), false).OfType<SendMethodKeyAttribute>().First().Key; var barkKey = typeof(BarkSendTemplate).GetCustomAttributes(typeof(SendMethodKeyAttribute), false).OfType<SendMethodKeyAttribute>().First().Key;
if (barkKey == inputTemeplate.Key) if (barkKey == inputTemeplate.Type)
{ {
return Fail(406, "BARK通道勿手动添加请使用APP添加BARK地址绑定"); return Fail(406, "BARK通道勿手动添加请使用APP添加BARK地址绑定");
} }
@ -109,9 +111,10 @@ namespace Inotify.Controllers
var sendAuth = new SendAuthInfo() var sendAuth = new SendAuthInfo()
{ {
UserId = userInfo.Id, UserId = userInfo.Id,
SendMethodTemplate = inputTemeplate.Key, SendMethodTemplate = inputTemeplate.Type,
AuthData = authInfo, AuthData = authInfo,
Name = inputTemeplate.Name, Name = inputTemeplate.Name,
Key = Guid.NewGuid().ToString("N").ToUpper(),
CreateTime = DateTime.Now, CreateTime = DateTime.Now,
ModifyTime = DateTime.Now, ModifyTime = DateTime.Now,
}; };

View File

@ -136,12 +136,18 @@ namespace Inotify.Data
return false; return false;
} }
public bool IsSendKey(string key, out bool isActive) public bool IsSendKey(string key, out bool isActive, out string token)
{ {
isActive = false; isActive = false;
token = null;
var sendAuthInfo = DBase.Query<SendAuthInfo>().FirstOrDefault(e => e.Key == key); var sendAuthInfo = DBase.Query<SendAuthInfo>().FirstOrDefault(e => e.Key == key);
if (sendAuthInfo != null) if (sendAuthInfo != null)
{ {
var userInfo = DBase.Query<SendUserInfo>().FirstOrDefault(e => e.Id == sendAuthInfo.UserId);
if (userInfo != null&& userInfo.Token!=null)
{
token = userInfo.Token;
}
isActive = sendAuthInfo.Active; isActive = sendAuthInfo.Active;
return true; return true;
} }
@ -219,6 +225,7 @@ namespace Inotify.Data
var builder = new MigrationBuilder(MigrationName, DBase); var builder = new MigrationBuilder(MigrationName, DBase);
builder.Append(new Version(2, 0, 0, 0), new V2UpdateMigration()); builder.Append(new Version(2, 0, 0, 0), new V2UpdateMigration());
builder.Append(new Version(2, 0, 0, 1), new V2001UpdateMigration()); builder.Append(new Version(2, 0, 0, 1), new V2001UpdateMigration());
builder.Append(new Version(2, 0, 0, 4), new V2004UpdateMigration());
builder.Execute(); builder.Execute();
} }
} }

View File

@ -80,7 +80,6 @@ namespace Inotify.Data
protected override void execute() protected override void execute()
{ {
//对AuthInfo的AuthDate字段进行加密
var sendAuthInfos = Migrator.Database.Query<SendAuthInfo>().ToList(); var sendAuthInfos = Migrator.Database.Query<SendAuthInfo>().ToList();
sendAuthInfos.ForEach(sendAuthInfo => sendAuthInfos.ForEach(sendAuthInfo =>
{ {
@ -88,7 +87,6 @@ namespace Inotify.Data
Migrator.Database.Update(sendAuthInfo); Migrator.Database.Update(sendAuthInfo);
}); });
//添加bark密钥相关内容
Migrator.Database.Insert(new SystemInfo() Migrator.Database.Insert(new SystemInfo()
{ {
key = "barkKeyId", key = "barkKeyId",
@ -106,4 +104,18 @@ namespace Inotify.Data
}); });
} }
} }
public class V2004UpdateMigration : Migration, IMigration
{
protected override void execute()
{
var sendAuthInfos = Migrator.Database.Query<SendAuthInfo>().ToList();
sendAuthInfos.ForEach(sendAuthInfo =>
{
if (string.IsNullOrEmpty(sendAuthInfo.Key))
sendAuthInfo.Key = Guid.NewGuid().ToString("N").ToUpper();
Migrator.Database.Update(sendAuthInfo);
});
}
}
} }

View File

@ -6,8 +6,8 @@
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<StartupObject>Inotify.Program</StartupObject> <StartupObject>Inotify.Program</StartupObject>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AssemblyVersion>2.0.0.3</AssemblyVersion> <AssemblyVersion>2.0.0.4</AssemblyVersion>
<FileVersion>2.0.0.3</FileVersion> <FileVersion>2.0.0.4</FileVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@ -124,9 +124,9 @@ namespace Inotify.Sends
var getTemeplateMethod = sendMethodTemplateType.GetMethod("GetTemeplate"); var getTemeplateMethod = sendMethodTemplateType.GetMethod("GetTemeplate");
if (getTemeplateMethod != null) if (getTemeplateMethod != null)
{ {
if (getTemeplateMethod.Invoke(obj, null) is InputTemeplate temeplate && temeplate.Key != null) if (getTemeplateMethod.Invoke(obj, null) is InputTemeplate temeplate && temeplate.Type != null)
{ {
sendTemplates.Add(temeplate.Key, temeplate); sendTemplates.Add(temeplate.Type, temeplate);
} }
} }
} }

View File

@ -62,8 +62,9 @@ namespace Inotify.Sends
public class InputTemeplate public class InputTemeplate
{ {
public string? Key { get; set; }
public string? Type { get; set; } public string? Type { get; set; }
public string? TypeName { get; set; }
public string? Key { get; set; }
public string? Name { get; set; } public string? Name { get; set; }
public bool IsActive { get; set; } public bool IsActive { get; set; }
public string Warning { get; set; } public string Warning { get; set; }
@ -179,9 +180,10 @@ namespace Inotify.Sends
{ {
return new InputTemeplate() return new InputTemeplate()
{ {
Key = "",
Name = sendMethodKeyAttribute.Name, Name = sendMethodKeyAttribute.Name,
Type = sendMethodKeyAttribute.Name, Type = sendMethodKeyAttribute.Key,
Key = sendMethodKeyAttribute.Key, TypeName = sendMethodKeyAttribute.Name,
Warning = sendMethodKeyAttribute.Waring, Warning = sendMethodKeyAttribute.Waring,
Values = values Values = values
}; };

View File

@ -109,7 +109,7 @@ namespace Inotify
if (match.Success) if (match.Success)
{ {
rewriteContext.HttpContext.Request.Path = @"/api/send"; rewriteContext.HttpContext.Request.Path = @"/api/send";
rewriteContext.HttpContext.Request.QueryString = new QueryString($"?token={groups[1]}&key={groups[2]}&title={groups[3]}&date={groups[4]}"); rewriteContext.HttpContext.Request.QueryString = new QueryString($"?key={groups[2]}&title={groups[3]}&date={groups[4]}");
} }
else else
{ {
@ -117,7 +117,7 @@ namespace Inotify
if (match.Success) if (match.Success)
{ {
rewriteContext.HttpContext.Request.Path = @"/api/send"; rewriteContext.HttpContext.Request.Path = @"/api/send";
rewriteContext.HttpContext.Request.QueryString = new QueryString($"?token={groups[1]}&key={groups[2]}&title={groups[3]}"); rewriteContext.HttpContext.Request.QueryString = new QueryString($"?key={groups[2]}&title={groups[3]}");
} }
else else
{ {
@ -125,7 +125,7 @@ namespace Inotify
if (match.Success) if (match.Success)
{ {
rewriteContext.HttpContext.Request.Path = @"/api/send"; rewriteContext.HttpContext.Request.Path = @"/api/send";
rewriteContext.HttpContext.Request.QueryString = new QueryString($"?token={groups[1]}&key={groups[2]}"); rewriteContext.HttpContext.Request.QueryString = new QueryString($"?key={groups[2]}");
} }
else if (rewriteContext.HttpContext.Request.QueryString.Value.StartsWith("?")) else if (rewriteContext.HttpContext.Request.QueryString.Value.StartsWith("?"))
{ {

View File

@ -38,6 +38,8 @@
* V2.0.0.3 * V2.0.0.3
* 支持钉钉群消息 * 支持钉钉群消息
* 支持飞书群消息 * 支持飞书群消息
* V2.0.0.4
* 支持通道独立消息推送
## 使用方法 ## 使用方法
1. Docker安装 1. Docker安装
@ -45,7 +47,7 @@
``` ```
docker run --name=inotify -d -p 8000:80 -v inotify_data:/inotify_data --restart=always xpnas/inotify:latest docker run --name=inotify -d -p 8000:80 -v inotify_data:/inotify_data --restart=always xpnas/inotify:latest
``` ```
* 开发版V2.0.0.3 * 开发版V2.0.0.4
``` ```
docker run --name=inotify -d -p 8000:80 -v inotify_data:/inotify_data --restart=always xpnas/inotify:master docker run --name=inotify -d -p 8000:80 -v inotify_data:/inotify_data --restart=always xpnas/inotify:master
``` ```