mirror of https://github.com/openspug/spug
# 推送服务设置支持解绑
parent
3d83dbb117
commit
3d3697e47b
|
@ -13,5 +13,6 @@ urlpatterns = [
|
||||||
url(r'^email_test/$', email_test),
|
url(r'^email_test/$', email_test),
|
||||||
url(r'^mfa/$', MFAView.as_view()),
|
url(r'^mfa/$', MFAView.as_view()),
|
||||||
url(r'^about/$', get_about),
|
url(r'^about/$', get_about),
|
||||||
url(r'^balance/$', get_push_balance),
|
url(r'^push/bind/$', handle_push_bind),
|
||||||
|
url(r'^push/balance/$', handle_push_balance),
|
||||||
]
|
]
|
||||||
|
|
|
@ -31,6 +31,10 @@ class AppSetting:
|
||||||
else:
|
else:
|
||||||
raise KeyError('invalid key')
|
raise KeyError('invalid key')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete(cls, key):
|
||||||
|
Setting.objects.filter(key=key).delete()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_ssh_key(cls):
|
def get_ssh_key(cls):
|
||||||
public_key = cls.get_default('public_key')
|
public_key = cls.get_default('public_key')
|
||||||
|
|
|
@ -21,7 +21,10 @@ class SettingView(AdminView):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
response = deepcopy(KEYS_DEFAULT)
|
response = deepcopy(KEYS_DEFAULT)
|
||||||
for item in Setting.objects.all():
|
for item in Setting.objects.all():
|
||||||
response[item.key] = item.real_val
|
if item.key == 'spug_push_key':
|
||||||
|
response[item.key] = f'{item.real_val[:8]}********{item.real_val[-8:]}'
|
||||||
|
else:
|
||||||
|
response[item.key] = item.real_val
|
||||||
return json_response(response)
|
return json_response(response)
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
|
@ -126,7 +129,27 @@ def get_about(request):
|
||||||
|
|
||||||
|
|
||||||
@auth('admin')
|
@auth('admin')
|
||||||
def get_push_balance(request):
|
def handle_push_bind(request):
|
||||||
|
form, error = JsonParser(
|
||||||
|
Argument('spug_push_key', required=False),
|
||||||
|
).parse(request.body)
|
||||||
|
if error is None:
|
||||||
|
if not form.spug_push_key:
|
||||||
|
AppSetting.delete('spug_push_key')
|
||||||
|
return json_response()
|
||||||
|
|
||||||
|
try:
|
||||||
|
res = get_balance(form.spug_push_key)
|
||||||
|
except Exception as e:
|
||||||
|
return json_response(error=f'绑定失败:{e}')
|
||||||
|
|
||||||
|
AppSetting.set('spug_push_key', form.spug_push_key)
|
||||||
|
return json_response(res)
|
||||||
|
return json_response(error=error)
|
||||||
|
|
||||||
|
|
||||||
|
@auth('admin')
|
||||||
|
def handle_push_balance(request):
|
||||||
token = AppSetting.get_default('spug_push_key')
|
token = AppSetting.get_default('spug_push_key')
|
||||||
if not token:
|
if not token:
|
||||||
return json_response(error='请先配置推送服务绑定账户')
|
return json_response(error='请先配置推送服务绑定账户')
|
||||||
|
|
|
@ -14,17 +14,18 @@ import store from './store';
|
||||||
export default observer(function () {
|
export default observer(function () {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [fetching, setFetching] = useState(false);
|
const [fetching, setFetching] = useState(false);
|
||||||
const [balance, setBalance] = useState({})
|
const [balance, setBalance] = useState({});
|
||||||
|
const [pushKey, setPushKey] = useState(store.settings.spug_push_key);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (store.settings.spug_push_key) {
|
if (pushKey) {
|
||||||
fetchBalance()
|
fetchBalance()
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function fetchBalance() {
|
function fetchBalance() {
|
||||||
setFetching(true)
|
setFetching(true)
|
||||||
http.get('/api/setting/balance/')
|
http.get('/api/setting/push/balance/')
|
||||||
.then(res => setBalance(res))
|
.then(res => setBalance(res))
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
|
@ -33,19 +34,31 @@ export default observer(function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBind() {
|
function handleBind() {
|
||||||
const spug_push_key = store.settings.spug_push_key
|
if (!pushKey) return message.error('请输入要绑定的推送助手用户ID')
|
||||||
if (!spug_push_key) return message.error('请输入要绑定的推送助手用户ID')
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
http.post('/api/setting/', {data: [{key: 'spug_push_key', value: spug_push_key}]})
|
http.post('/api/setting/push/bind/', {spug_push_key: pushKey})
|
||||||
.then(() => {
|
.then(res => {
|
||||||
message.success('保存成功');
|
message.success('绑定成功');
|
||||||
store.fetchSettings();
|
store.fetchSettings();
|
||||||
fetchBalance()
|
setBalance(res)
|
||||||
})
|
})
|
||||||
.finally(() => store.loading = false)
|
.finally(() => setLoading(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
const isVip = true
|
function handleUnbind() {
|
||||||
|
setLoading(true);
|
||||||
|
http.post('/api/setting/push/bind/', {spug_push_key: ''})
|
||||||
|
.then(() => {
|
||||||
|
message.success('解绑成功');
|
||||||
|
store.fetchSettings();
|
||||||
|
setBalance({})
|
||||||
|
setPushKey('')
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
const isVip = balance.is_vip
|
||||||
|
const spugPushKey = store.settings.spug_push_key
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className={css.title}>推送服务设置</div>
|
<div className={css.title}>推送服务设置</div>
|
||||||
|
@ -54,61 +67,73 @@ export default observer(function () {
|
||||||
extra={<div>请登录 <Link href="https://push.spug.cc/login" title="推送助手"/>,至个人中心 /
|
extra={<div>请登录 <Link href="https://push.spug.cc/login" title="推送助手"/>,至个人中心 /
|
||||||
个人设置查看用户ID,注意保密该ID请勿泄漏给第三方。</div>}>
|
个人设置查看用户ID,注意保密该ID请勿泄漏给第三方。</div>}>
|
||||||
|
|
||||||
<Input.Group compact>
|
{spugPushKey ? (
|
||||||
<Input
|
<Input.Group compact>
|
||||||
value={store.settings.spug_push_key}
|
<div className={css.keyText}
|
||||||
onChange={e => store.settings.spug_push_key = e.target.value}
|
style={{width: 'calc(100% - 100px)', lineHeight: '32px', fontWeight: 'bold'}}>{spugPushKey}</div>
|
||||||
style={{width: 'calc(100% - 100px)'}}
|
<Button
|
||||||
placeholder="请输入要绑定的推送助手用户ID"/>
|
ghost
|
||||||
<Button
|
type="danger"
|
||||||
type="primary"
|
style={{width: 80, marginLeft: 20}}
|
||||||
style={{width: 80, marginLeft: 20}}
|
onClick={handleUnbind}
|
||||||
onClick={handleBind}
|
loading={loading}>解绑</Button>
|
||||||
loading={loading}>确定</Button>
|
</Input.Group>
|
||||||
</Input.Group>
|
) : (
|
||||||
{/*<Input.Group compact>*/}
|
<Input.Group compact>
|
||||||
{/* <Input bordered={false} style={{width: 'calc(100% - 100px)', paddingLeft: 0}} value="32uu73******64823d"/>*/}
|
<Input
|
||||||
{/* <Button style={{width: 80, marginLeft: 20}}>解绑</Button>*/}
|
value={pushKey}
|
||||||
{/*</Input.Group>*/}
|
onChange={e => setPushKey(e.target.value)}
|
||||||
|
style={{width: 'calc(100% - 100px)'}}
|
||||||
|
placeholder="请输入要绑定的推送助手用户ID"/>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
style={{width: 80, marginLeft: 20}}
|
||||||
|
onClick={handleBind}
|
||||||
|
loading={loading}>确定</Button>
|
||||||
|
</Input.Group>
|
||||||
|
|
||||||
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Form.Item style={{marginTop: 24}}
|
{spugPushKey ? (
|
||||||
extra={<div> 如需充值请至 <Link href="https://push.spug.cc/buy/sms" title="推送助手"/>,具体计费规则及说明请查看推送助手官网。
|
<Form.Item style={{marginTop: 24}}
|
||||||
</div>}>
|
extra={<div> 如需充值请至 <Link href="https://push.spug.cc/buy/sms" title="推送助手"/>,具体计费规则及说明请查看推送助手官网。
|
||||||
<div className={css.statistic}>
|
</div>}>
|
||||||
<Spin spinning={fetching}>
|
<div className={css.statistic}>
|
||||||
<div className={css.body}>
|
<Spin spinning={fetching}>
|
||||||
<div className={css.item}>
|
<div className={css.body}>
|
||||||
<div className={css.title}>短信余额</div>
|
<div className={css.item}>
|
||||||
<div className={css.value}>{balance.sms_balance}</div>
|
<div className={css.title}>短信余额</div>
|
||||||
|
<div className={css.value}>{balance.sms_balance}</div>
|
||||||
|
</div>
|
||||||
|
<div className={css.item}>
|
||||||
|
<div className={css.title}>语音余额</div>
|
||||||
|
<div className={css.value}>{balance.voice_balance}</div>
|
||||||
|
</div>
|
||||||
|
<div className={css.item}>
|
||||||
|
<div className={css.title}>邮件余额</div>
|
||||||
|
<div className={css.value}>{balance.mail_balance}</div>
|
||||||
|
{isVip ? (
|
||||||
|
<div className={clsNames(css.tips, css.active)}>+ 会员免费20封 / 天</div>
|
||||||
|
) : (
|
||||||
|
<div className={css.tips}>会员免费20封 / 天</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={css.item}>
|
||||||
|
<div className={css.title}>微信公众号余额</div>
|
||||||
|
<div className={css.value}>{balance.wx_mp_balance}</div>
|
||||||
|
{isVip ? (
|
||||||
|
<div className={clsNames(css.tips, css.active)}>+ 会员免费100条 / 天</div>
|
||||||
|
) : (
|
||||||
|
<div className={css.tips}>会员免费20封 / 天</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={css.item}>
|
</Spin>
|
||||||
<div className={css.title}>语音余额</div>
|
</div>
|
||||||
<div className={css.value}>{balance.voice_balance}</div>
|
</Form.Item>
|
||||||
</div>
|
) : null}
|
||||||
<div className={css.item}>
|
|
||||||
<div className={css.title}>邮件余额</div>
|
|
||||||
<div className={css.value}>{balance.mail_balance}</div>
|
|
||||||
{isVip ? (
|
|
||||||
<div className={clsNames(css.tips, css.active)}>+ 会员免费20封 / 天</div>
|
|
||||||
) : (
|
|
||||||
<div className={css.tips}>会员免费20封 / 天</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className={css.item}>
|
|
||||||
<div className={css.title}>微信公众号余额</div>
|
|
||||||
<div className={css.value}>{balance.wx_mp_balance}</div>
|
|
||||||
{isVip ? (
|
|
||||||
<div className={clsNames(css.tips, css.active)}>+ 会员免费100条 / 天</div>
|
|
||||||
) : (
|
|
||||||
<div className={css.tips}>会员免费20封 / 天</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Spin>
|
|
||||||
</div>
|
|
||||||
</Form.Item>
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
})
|
})
|
Loading…
Reference in New Issue