mirror of https://github.com/openspug/spug
U 安全性改进
parent
282f785928
commit
2b33df0765
|
@ -3,11 +3,12 @@
|
|||
# Released under the AGPL-3.0 License.
|
||||
from django.views.generic import View
|
||||
from django.db.models import F
|
||||
from libs import json_response
|
||||
from libs import json_response, auth
|
||||
from apps.account.models import History
|
||||
|
||||
|
||||
class HistoryView(View):
|
||||
@auth('dashboard.dashboard.view')
|
||||
def get(self, request):
|
||||
histories = []
|
||||
for item in History.objects.annotate(nickname=F('user__nickname')):
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# Copyright: (c) <spug.dev@gmail.com>
|
||||
# Released under the AGPL-3.0 License.
|
||||
from django.db import models
|
||||
from django.core.cache import cache
|
||||
from libs import ModelMixin, human_datetime
|
||||
from django.contrib.auth.hashers import make_password, check_password
|
||||
import json
|
||||
|
@ -33,16 +34,25 @@ class User(models.Model, ModelMixin):
|
|||
def verify_password(self, plain_password: str) -> bool:
|
||||
return check_password(plain_password, self.password_hash)
|
||||
|
||||
def get_perms_cache(self):
|
||||
return cache.get(f'perms_{self.id}', set())
|
||||
|
||||
def set_perms_cache(self, value=None):
|
||||
cache.set(f'perms_{self.id}', value or set())
|
||||
|
||||
@property
|
||||
def page_perms(self):
|
||||
data = set()
|
||||
data = self.get_perms_cache()
|
||||
if data:
|
||||
return data
|
||||
for item in self.roles.all():
|
||||
if item.page_perms:
|
||||
perms = json.loads(item.page_perms)
|
||||
for m, v in perms.items():
|
||||
for p, d in v.items():
|
||||
data.update(f'{m}.{p}.{x}' for x in d)
|
||||
return list(data)
|
||||
self.set_perms_cache(data)
|
||||
return data
|
||||
|
||||
@property
|
||||
def deploy_perms(self):
|
||||
|
@ -63,8 +73,9 @@ class User(models.Model, ModelMixin):
|
|||
return list(data)
|
||||
|
||||
def has_perms(self, codes):
|
||||
# return self.is_supper or self.role in codes
|
||||
return self.is_supper
|
||||
if self.is_supper:
|
||||
return True
|
||||
return self.page_perms.intersection(codes)
|
||||
|
||||
def __repr__(self):
|
||||
return '<User %r>' % self.username
|
||||
|
@ -99,6 +110,10 @@ class Role(models.Model, ModelMixin):
|
|||
self.deploy_perms = json.dumps(perms)
|
||||
self.save()
|
||||
|
||||
def clear_perms_cache(self):
|
||||
for item in self.user_set.all():
|
||||
item.set_perms_cache()
|
||||
|
||||
def __repr__(self):
|
||||
return '<Role name=%r>' % self.name
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# Copyright: (c) <spug.dev@gmail.com>
|
||||
# Released under the AGPL-3.0 License.
|
||||
from django.core.cache import cache
|
||||
from django.views.generic import View
|
||||
from libs.mixins import AdminView, View
|
||||
from libs import JsonParser, Argument, human_datetime, json_response
|
||||
from libs.utils import get_request_real_ip, generate_random_str
|
||||
from libs.spug import send_login_wx_code
|
||||
|
@ -15,7 +15,7 @@ import uuid
|
|||
import json
|
||||
|
||||
|
||||
class UserView(View):
|
||||
class UserView(AdminView):
|
||||
def get(self, request):
|
||||
users = []
|
||||
for u in User.objects.filter(deleted_by_id__isnull=True):
|
||||
|
@ -50,6 +50,7 @@ class UserView(View):
|
|||
**form
|
||||
)
|
||||
user.roles.set(role_ids)
|
||||
user.set_perms_cache()
|
||||
return json_response(error=error)
|
||||
|
||||
def patch(self, request):
|
||||
|
@ -88,7 +89,7 @@ class UserView(View):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
class RoleView(View):
|
||||
class RoleView(AdminView):
|
||||
def get(self, request):
|
||||
roles = Role.objects.all()
|
||||
return json_response(roles)
|
||||
|
@ -119,6 +120,7 @@ class RoleView(View):
|
|||
return json_response(error='未找到指定角色')
|
||||
if form.page_perms is not None:
|
||||
role.page_perms = json.dumps(form.page_perms)
|
||||
role.clear_perms_cache()
|
||||
if form.deploy_perms is not None:
|
||||
role.deploy_perms = json.dumps(form.deploy_perms)
|
||||
if form.group_perms is not None:
|
||||
|
@ -240,7 +242,7 @@ def handle_user_info(request, user, captcha):
|
|||
'nickname': user.nickname,
|
||||
'is_supper': user.is_supper,
|
||||
'has_real_ip': x_real_ip and ipaddress.ip_address(x_real_ip).is_global if verify_ip else True,
|
||||
'permissions': [] if user.is_supper else user.page_perms
|
||||
'permissions': [] if user.is_supper else list(user.page_perms)
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -2,23 +2,26 @@
|
|||
# Copyright: (c) <spug.dev@gmail.com>
|
||||
# Released under the AGPL-3.0 License.
|
||||
from django.views.generic import View
|
||||
from libs import json_response, JsonParser, Argument
|
||||
from libs import json_response, JsonParser, Argument, auth
|
||||
from apps.alarm.models import Alarm, Group, Contact
|
||||
from apps.monitor.models import Detection
|
||||
import json
|
||||
|
||||
|
||||
class AlarmView(View):
|
||||
@auth('alarm.alarm.view')
|
||||
def get(self, request):
|
||||
alarms = Alarm.objects.all()
|
||||
return json_response(alarms)
|
||||
|
||||
|
||||
class GroupView(View):
|
||||
@auth('alarm.group.view|monitor.monitor.add|monitor.monitor.edit|alarm.alarm.view')
|
||||
def get(self, request):
|
||||
groups = Group.objects.all()
|
||||
return json_response(groups)
|
||||
|
||||
@auth('alarm.group.add|alarm.group.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -35,6 +38,7 @@ class GroupView(View):
|
|||
Group.objects.create(**form)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('alarm.group.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象')
|
||||
|
@ -48,10 +52,12 @@ class GroupView(View):
|
|||
|
||||
|
||||
class ContactView(View):
|
||||
@auth('alarm.contact.view|alarm.group.view')
|
||||
def get(self, request):
|
||||
contacts = Contact.objects.all()
|
||||
return json_response(contacts)
|
||||
|
||||
@auth('alarm.contact.add|alarm.contact.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -70,6 +76,7 @@ class ContactView(View):
|
|||
Contact.objects.create(**form)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('alarm.contact.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象')
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Released under the AGPL-3.0 License.
|
||||
from django.views.generic import View
|
||||
from django.db.models import F
|
||||
from libs import JsonParser, Argument, json_response
|
||||
from libs import JsonParser, Argument, json_response, auth
|
||||
from apps.app.models import App, Deploy, DeployExtend1, DeployExtend2
|
||||
from apps.config.models import Config
|
||||
from apps.app.utils import fetch_versions, remove_repo
|
||||
|
@ -13,6 +13,7 @@ import re
|
|||
|
||||
|
||||
class AppView(View):
|
||||
@auth('deploy.app.view|deploy.repository.view|deploy.request.view|config.app.view')
|
||||
def get(self, request):
|
||||
query = {}
|
||||
if not request.user.is_supper:
|
||||
|
@ -20,6 +21,7 @@ class AppView(View):
|
|||
apps = App.objects.filter(**query)
|
||||
return json_response(apps)
|
||||
|
||||
@auth('deploy.app.edit|config.app.add|config.app.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -42,6 +44,7 @@ class AppView(View):
|
|||
app.save()
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('deploy.app.edit|config.app.edit_config')
|
||||
def patch(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='参数错误'),
|
||||
|
@ -68,6 +71,7 @@ class AppView(View):
|
|||
app.save()
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('deploy.app.del|config.app.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象')
|
||||
|
@ -82,6 +86,7 @@ class AppView(View):
|
|||
|
||||
|
||||
class DeployView(View):
|
||||
@auth('deploy.app.view|deploy.request.view')
|
||||
def get(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('app_id', type=int, required=False)
|
||||
|
@ -95,6 +100,7 @@ class DeployView(View):
|
|||
.order_by('-app__sort_id')
|
||||
return json_response(deploys)
|
||||
|
||||
@auth('deploy.app.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -157,6 +163,7 @@ class DeployView(View):
|
|||
DeployExtend2.objects.create(deploy=deploy, **extend_form)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('deploy.app.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象')
|
||||
|
@ -171,6 +178,7 @@ class DeployView(View):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('deploy.app.config')
|
||||
def get_versions(request, d_id):
|
||||
deploy = Deploy.objects.filter(pk=d_id).first()
|
||||
if not deploy:
|
||||
|
@ -181,6 +189,7 @@ def get_versions(request, d_id):
|
|||
return json_response({'branches': branches, 'tags': tags})
|
||||
|
||||
|
||||
@auth('deploy.app.config')
|
||||
def kit_key(request):
|
||||
api_key = AppSetting.get_default('api_key')
|
||||
return json_response(api_key)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Released under the AGPL-3.0 License.
|
||||
from django.views.generic import View
|
||||
from django.db.models import F
|
||||
from libs import json_response, JsonParser, Argument
|
||||
from libs import json_response, JsonParser, Argument, auth
|
||||
from apps.app.models import Deploy
|
||||
from apps.config.models import *
|
||||
import json
|
||||
|
@ -11,6 +11,7 @@ import re
|
|||
|
||||
|
||||
class EnvironmentView(View):
|
||||
@auth('deploy.repository.view|deploy.request.view|config.env.view')
|
||||
def get(self, request):
|
||||
query = {}
|
||||
if not request.user.is_supper:
|
||||
|
@ -18,6 +19,7 @@ class EnvironmentView(View):
|
|||
envs = Environment.objects.filter(**query)
|
||||
return json_response(envs)
|
||||
|
||||
@auth('config.env.add|config.env.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -40,6 +42,7 @@ class EnvironmentView(View):
|
|||
env.save()
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('config.env.edit')
|
||||
def patch(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='参数错误'),
|
||||
|
@ -60,6 +63,7 @@ class EnvironmentView(View):
|
|||
env.save()
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('config.env.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象')
|
||||
|
@ -74,10 +78,12 @@ class EnvironmentView(View):
|
|||
|
||||
|
||||
class ServiceView(View):
|
||||
@auth('config.src.view')
|
||||
def get(self, request):
|
||||
services = Service.objects.all()
|
||||
return json_response(services)
|
||||
|
||||
@auth('config.src.add|config.src.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -98,6 +104,7 @@ class ServiceView(View):
|
|||
Service.objects.create(created_by=request.user, **form)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('config.src.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象')
|
||||
|
@ -110,6 +117,7 @@ class ServiceView(View):
|
|||
|
||||
|
||||
class ConfigView(View):
|
||||
@auth('config.src.view_config|config.app.view_config')
|
||||
def get(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='未指定操作对象'),
|
||||
|
@ -125,6 +133,7 @@ class ConfigView(View):
|
|||
return json_response(data)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('config.src.edit_config|config.app.edit_config')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('o_id', type=int, help='缺少必要参数'),
|
||||
|
@ -148,6 +157,7 @@ class ConfigView(View):
|
|||
ConfigHistory.objects.create(action='1', env_id=env_id, **form)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('config.src.edit_config|config.app.edit_config')
|
||||
def patch(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='缺少必要参数'),
|
||||
|
@ -174,6 +184,7 @@ class ConfigView(View):
|
|||
config.save()
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('config.src.edit_config|config.app.edit_config')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='未指定操作对象')
|
||||
|
@ -194,6 +205,7 @@ class ConfigView(View):
|
|||
|
||||
|
||||
class HistoryView(View):
|
||||
@auth('config.src.view_config|config.app.view_config')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('o_id', type=int, help='缺少必要参数'),
|
||||
|
@ -211,6 +223,7 @@ class HistoryView(View):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('config.src.view_config|config.app.view_config')
|
||||
def post_diff(request):
|
||||
form, error = JsonParser(
|
||||
Argument('o_id', type=int, help='缺少必要参数'),
|
||||
|
@ -228,6 +241,7 @@ def post_diff(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('config.src.edit_config|config.app.edit_config')
|
||||
def parse_json(request):
|
||||
form, error = JsonParser(
|
||||
Argument('o_id', type=int, help='缺少必要参数'),
|
||||
|
@ -241,6 +255,7 @@ def parse_json(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('config.src.edit_config|config.app.edit_config')
|
||||
def parse_text(request):
|
||||
form, error = JsonParser(
|
||||
Argument('o_id', type=int, help='缺少必要参数'),
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.db.models import F
|
|||
from django.conf import settings
|
||||
from django.http.response import HttpResponseBadRequest
|
||||
from django_redis import get_redis_connection
|
||||
from libs import json_response, JsonParser, Argument, human_datetime, human_time
|
||||
from libs import json_response, JsonParser, Argument, human_datetime, human_time, auth
|
||||
from apps.deploy.models import DeployRequest
|
||||
from apps.app.models import Deploy, DeployExtend2
|
||||
from apps.repository.models import Repository
|
||||
|
@ -21,6 +21,7 @@ import os
|
|||
|
||||
|
||||
class RequestView(View):
|
||||
@auth('deploy.request.view')
|
||||
def get(self, request):
|
||||
data, query, counter = [], {}, {}
|
||||
if not request.user.is_supper:
|
||||
|
@ -54,37 +55,7 @@ class RequestView(View):
|
|||
data.append(tmp)
|
||||
return json_response(data)
|
||||
|
||||
def put(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='缺少必要参数'),
|
||||
Argument('action', filter=lambda x: x in ('check', 'do'), help='参数错误')
|
||||
).parse(request.body)
|
||||
if error is None:
|
||||
req = DeployRequest.objects.filter(pk=form.id).first()
|
||||
if not req:
|
||||
return json_response(error='未找到指定发布申请')
|
||||
pre_req = DeployRequest.objects.filter(
|
||||
deploy_id=req.deploy_id,
|
||||
type='1',
|
||||
id__lt=req.id,
|
||||
version__isnull=False).first()
|
||||
if not pre_req:
|
||||
return json_response(error='未找到该应用可以用于回滚的版本')
|
||||
if form.action == 'check':
|
||||
return json_response({'date': pre_req.created_at, 'name': pre_req.name})
|
||||
DeployRequest.objects.create(
|
||||
deploy_id=req.deploy_id,
|
||||
name=f'{req.name} - 回滚',
|
||||
type='2',
|
||||
extra=pre_req.extra,
|
||||
host_ids=req.host_ids,
|
||||
status='0' if pre_req.deploy.is_audit else '1',
|
||||
desc='自动回滚至该应用的上个版本',
|
||||
version=pre_req.version,
|
||||
created_by=request.user
|
||||
)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('deploy.request.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -123,6 +94,7 @@ class RequestView(View):
|
|||
|
||||
|
||||
class RequestDetailView(View):
|
||||
@auth('deploy.request.view')
|
||||
def get(self, request, r_id):
|
||||
req = DeployRequest.objects.filter(pk=r_id).first()
|
||||
if not req:
|
||||
|
@ -160,6 +132,7 @@ class RequestDetailView(View):
|
|||
outputs['local'].update(step=100, data=f'{human_time()} 已构建完成忽略执行。')
|
||||
return json_response(response)
|
||||
|
||||
@auth('deploy.request.do')
|
||||
def post(self, request, r_id):
|
||||
query = {'pk': r_id}
|
||||
if not request.user.is_supper:
|
||||
|
@ -194,6 +167,7 @@ class RequestDetailView(View):
|
|||
return json_response({'s_actions': s_actions, 'h_actions': h_actions, 'outputs': outputs})
|
||||
return json_response({'outputs': outputs})
|
||||
|
||||
@auth('deploy.request.approve')
|
||||
def patch(self, request, r_id):
|
||||
form, error = JsonParser(
|
||||
Argument('reason', required=False),
|
||||
|
@ -216,6 +190,7 @@ class RequestDetailView(View):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('deploy.request.add|deploy.request.edit')
|
||||
def post_request_ext1(request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -264,6 +239,7 @@ def post_request_ext1(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('deploy.request.do')
|
||||
def post_request_ext1_rollback(request):
|
||||
form, error = JsonParser(
|
||||
Argument('request_id', type=int, help='请选择要回滚的版本'),
|
||||
|
@ -295,6 +271,7 @@ def post_request_ext1_rollback(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('deploy.request.add|deploy.request.edit')
|
||||
def post_request_ext2(request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -334,6 +311,7 @@ def post_request_ext2(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('deploy.request.view')
|
||||
def get_request_info(request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='参数错误')
|
||||
|
@ -346,6 +324,7 @@ def get_request_info(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('deploy.request.add')
|
||||
def do_upload(request):
|
||||
repos_dir = settings.REPOS_DIR
|
||||
file = request.FILES['file']
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
from django.views.generic import View
|
||||
from django_redis import get_redis_connection
|
||||
from django.conf import settings
|
||||
from libs import json_response, JsonParser, Argument, human_datetime
|
||||
from libs import json_response, JsonParser, Argument, human_datetime, auth
|
||||
from apps.exec.models import ExecTemplate
|
||||
from apps.host.models import Host
|
||||
from apps.account.utils import has_host_perm
|
||||
|
@ -13,11 +13,13 @@ import json
|
|||
|
||||
|
||||
class TemplateView(View):
|
||||
@auth('exec.template.view')
|
||||
def get(self, request):
|
||||
templates = ExecTemplate.objects.all()
|
||||
types = [x['type'] for x in templates.order_by('type').values('type').distinct()]
|
||||
return json_response({'types': types, 'templates': [x.to_dict() for x in templates]})
|
||||
|
||||
@auth('exec.template.add|exec.template.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -36,6 +38,7 @@ class TemplateView(View):
|
|||
ExecTemplate.objects.create(**form)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('exec.template.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象')
|
||||
|
@ -45,6 +48,7 @@ class TemplateView(View):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('exec.task.do')
|
||||
def do_task(request):
|
||||
form, error = JsonParser(
|
||||
Argument('host_ids', type=list, filter=lambda x: len(x), help='请选择执行主机'),
|
||||
|
|
|
@ -6,12 +6,13 @@ from django_redis import get_redis_connection
|
|||
from apps.host.models import Host
|
||||
from apps.account.utils import has_host_perm
|
||||
from apps.file.utils import FileResponseAfter, fetch_dir_list
|
||||
from libs import json_response, JsonParser, Argument
|
||||
from libs import json_response, JsonParser, Argument, auth
|
||||
from functools import partial
|
||||
import os
|
||||
|
||||
|
||||
class FileView(View):
|
||||
@auth('host.console.list')
|
||||
def get(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='参数错误'),
|
||||
|
@ -29,6 +30,7 @@ class FileView(View):
|
|||
|
||||
|
||||
class ObjectView(View):
|
||||
@auth('host.console.list')
|
||||
def get(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='参数错误'),
|
||||
|
@ -47,6 +49,7 @@ class ObjectView(View):
|
|||
return FileResponseAfter(ssh_cli.close, f, as_attachment=True, filename=filename)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('host.console.upload')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='参数错误'),
|
||||
|
@ -68,6 +71,7 @@ class ObjectView(View):
|
|||
ssh.put_file_by_fl(file, f'{form.path}/{file.name}', callback=callback)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('host.console.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='参数错误'),
|
||||
|
|
|
@ -11,10 +11,12 @@ from apps.deploy.models import Deploy, DeployRequest
|
|||
from apps.account.utils import get_host_perms
|
||||
from libs.utils import json_response, human_date, parse_time
|
||||
from libs.parser import JsonParser, Argument
|
||||
from libs.decorators import auth
|
||||
from datetime import datetime, timedelta
|
||||
import json
|
||||
|
||||
|
||||
@auth('dashboard.dashboard.view')
|
||||
def get_statistic(request):
|
||||
if request.user.is_supper:
|
||||
app = App.objects.count()
|
||||
|
@ -32,6 +34,7 @@ def get_statistic(request):
|
|||
return json_response(data)
|
||||
|
||||
|
||||
@auth('dashboard.dashboard.view')
|
||||
def get_alarm(request):
|
||||
form, error = JsonParser(
|
||||
Argument('type', required=False),
|
||||
|
@ -49,6 +52,7 @@ def get_alarm(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('dashboard.dashboard.view')
|
||||
def get_request(request):
|
||||
form, error = JsonParser(
|
||||
Argument('duration', type=list, help='参数错误')
|
||||
|
@ -64,6 +68,7 @@ def get_request(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('dashboard.dashboard.view')
|
||||
def get_deploy(request):
|
||||
host = Host.objects.filter(deleted_at__isnull=True).count()
|
||||
data = {x.id: {'name': x.name, 'count': 0} for x in App.objects.all()}
|
||||
|
@ -71,4 +76,3 @@ def get_deploy(request):
|
|||
data[dep.app_id]['count'] += len(json.loads(dep.host_ids))
|
||||
data = filter(lambda x: x['count'], data.values())
|
||||
return json_response({'host': host, 'res': list(data)})
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
# Copyright: (c) OpenSpug Organization. https://github.com/openspug/spug
|
||||
# Copyright: (c) <spug.dev@gmail.com>
|
||||
# Released under the AGPL-3.0 License.
|
||||
from libs import json_response, JsonParser, Argument
|
||||
from libs import json_response, JsonParser, Argument, auth
|
||||
from apps.host.models import Host, HostExtend, Group
|
||||
from apps.host import utils
|
||||
import json
|
||||
|
||||
|
||||
@auth('host.host.add')
|
||||
def get_regions(request):
|
||||
form, error = JsonParser(
|
||||
Argument('type', filter=lambda x: x in ('ali', 'tencent'), help='参数错误'),
|
||||
|
@ -25,6 +26,7 @@ def get_regions(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('host.host.add')
|
||||
def cloud_import(request):
|
||||
form, error = JsonParser(
|
||||
Argument('type', filter=lambda x: x in ('ali', 'tencent'), help='参数错误'),
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
# Copyright: (c) <spug.dev@gmail.com>
|
||||
# Released under the AGPL-3.0 License.
|
||||
from django.views.generic import View
|
||||
from libs import json_response, JsonParser, Argument, human_datetime
|
||||
from libs import json_response, JsonParser, Argument, human_datetime, auth
|
||||
from apps.host.models import Host, HostExtend
|
||||
from apps.host.utils import check_os_type, fetch_host_extend
|
||||
import json
|
||||
|
||||
|
||||
class ExtendView(View):
|
||||
@auth('host.host.add|host.host.edit')
|
||||
def get(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('host_id', type=int, help='参数错误')
|
||||
|
@ -24,6 +25,7 @@ class ExtendView(View):
|
|||
return json_response(response)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('host.host.add|host.host.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('host_id', type=int, help='参数错误'),
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Released under the AGPL-3.0 License.
|
||||
from django.views.generic import View
|
||||
from django.db.models import F
|
||||
from libs import json_response, JsonParser, Argument
|
||||
from libs import json_response, JsonParser, Argument, auth
|
||||
from apps.host.models import Group
|
||||
from apps.account.models import Role
|
||||
|
||||
|
@ -39,6 +39,7 @@ def filter_by_perm(data, result, ids):
|
|||
|
||||
|
||||
class GroupView(View):
|
||||
@auth('host.host.view|host.console.view|exec.task.do')
|
||||
def get(self, request):
|
||||
with_hosts = request.GET.get('with_hosts')
|
||||
data, data2 = dict(), dict()
|
||||
|
@ -56,6 +57,7 @@ class GroupView(View):
|
|||
merge_children(data2, '', tree_data)
|
||||
return json_response({'treeData': tree_data, 'groups': data2})
|
||||
|
||||
@auth('admin')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -71,6 +73,7 @@ class GroupView(View):
|
|||
group.save()
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('admin')
|
||||
def patch(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('s_id', type=int, help='参数错误'),
|
||||
|
@ -100,6 +103,7 @@ class GroupView(View):
|
|||
src.save()
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('admin')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='参数错误')
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
from django.views.generic import View
|
||||
from django.db.models import F
|
||||
from django.http.response import HttpResponseBadRequest
|
||||
from libs import json_response, JsonParser, Argument, AttrDict
|
||||
from libs import json_response, JsonParser, Argument, AttrDict, auth
|
||||
from apps.setting.utils import AppSetting
|
||||
from apps.account.utils import get_host_perms
|
||||
from apps.host.models import Host, Group
|
||||
|
@ -20,6 +20,7 @@ import uuid
|
|||
|
||||
|
||||
class HostView(View):
|
||||
@auth('host.host.view|exec.task.do')
|
||||
def get(self, request):
|
||||
hosts = Host.objects.select_related('hostextend')
|
||||
if not request.user.is_supper:
|
||||
|
@ -29,6 +30,7 @@ class HostView(View):
|
|||
hosts[rel.host_id]['group_ids'].append(rel.group_id)
|
||||
return json_response(list(hosts.values()))
|
||||
|
||||
@auth('host.host.add|host.host.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -76,6 +78,7 @@ class HostView(View):
|
|||
return json_response(response)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('admin')
|
||||
def patch(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('host_ids', type=list, filter=lambda x: len(x), help='请选择主机'),
|
||||
|
@ -93,6 +96,7 @@ class HostView(View):
|
|||
s_group.hosts.remove(*form.host_ids)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('host.host.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -122,6 +126,7 @@ class HostView(View):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('host.host.add')
|
||||
def post_import(request):
|
||||
group_id = request.POST.get('group_id')
|
||||
file = request.FILES['file']
|
||||
|
@ -152,6 +157,7 @@ def post_import(request):
|
|||
return json_response(summary)
|
||||
|
||||
|
||||
@auth('host.host.add')
|
||||
def post_parse(request):
|
||||
file = request.FILES['file']
|
||||
if file:
|
||||
|
@ -161,6 +167,7 @@ def post_parse(request):
|
|||
return HttpResponseBadRequest()
|
||||
|
||||
|
||||
@auth('host.host.add')
|
||||
def batch_valid(request):
|
||||
form, error = JsonParser(
|
||||
Argument('password', required=False),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# Copyright: (c) <spug.dev@gmail.com>
|
||||
# Released under the AGPL-3.0 License.
|
||||
from django.views.generic import View
|
||||
from libs import json_response, JsonParser, Argument, human_datetime
|
||||
from libs import json_response, JsonParser, Argument, human_datetime, auth
|
||||
from apps.monitor.models import Detection
|
||||
from django_redis import get_redis_connection
|
||||
from django.conf import settings
|
||||
|
@ -11,11 +11,13 @@ import json
|
|||
|
||||
|
||||
class DetectionView(View):
|
||||
@auth('dashboard.dashboard.view|monitor.monitor.view')
|
||||
def get(self, request):
|
||||
detections = Detection.objects.all()
|
||||
groups = [x['group'] for x in detections.order_by('group').values('group').distinct()]
|
||||
return json_response({'groups': groups, 'detections': [x.to_view() for x in detections]})
|
||||
|
||||
@auth('monitor.monitor.add|monitor.monitor.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -53,6 +55,7 @@ class DetectionView(View):
|
|||
rds_cli.lpush(settings.MONITOR_KEY, json.dumps(form))
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('monitor.monitor.edit')
|
||||
def patch(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象'),
|
||||
|
@ -71,6 +74,7 @@ class DetectionView(View):
|
|||
rds_cli.lpush(settings.MONITOR_KEY, json.dumps(message))
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('monitor.monitor.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象')
|
||||
|
@ -84,6 +88,7 @@ class DetectionView(View):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('monitor.monitor.add|monitor.monitor.edit')
|
||||
def run_test(request):
|
||||
form, error = JsonParser(
|
||||
Argument('type', help='请选择监控类型'),
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.views.generic import View
|
|||
from django.db.models import F
|
||||
from django.conf import settings
|
||||
from django_redis import get_redis_connection
|
||||
from libs import json_response, JsonParser, Argument, human_time, AttrDict
|
||||
from libs import json_response, JsonParser, Argument, human_time, AttrDict, auth
|
||||
from apps.repository.models import Repository
|
||||
from apps.deploy.models import DeployRequest
|
||||
from apps.repository.utils import dispatch
|
||||
|
@ -15,6 +15,7 @@ import json
|
|||
|
||||
|
||||
class RepositoryView(View):
|
||||
@auth('deploy.repository.view')
|
||||
def get(self, request):
|
||||
deploy_id = request.GET.get('deploy_id')
|
||||
data = Repository.objects.annotate(
|
||||
|
@ -35,6 +36,7 @@ class RepositoryView(View):
|
|||
response[item.app_id] = tmp
|
||||
return json_response(list(response.values()))
|
||||
|
||||
@auth('deploy.repository.add')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('deploy_id', type=int, help='参数错误'),
|
||||
|
@ -57,6 +59,7 @@ class RepositoryView(View):
|
|||
return json_response(rep.to_view())
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('deploy.repository.add|deploy.repository.build')
|
||||
def patch(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='参数错误'),
|
||||
|
@ -71,6 +74,7 @@ class RepositoryView(View):
|
|||
return json_response(rep.to_view())
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('deploy.repository.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象')
|
||||
|
@ -85,6 +89,7 @@ class RepositoryView(View):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('deploy.repository.view')
|
||||
def get_requests(request):
|
||||
form, error = JsonParser(
|
||||
Argument('repository_id', type=int, help='参数错误')
|
||||
|
@ -99,6 +104,7 @@ def get_requests(request):
|
|||
return json_response(requests)
|
||||
|
||||
|
||||
@auth('deploy.repository.view')
|
||||
def get_detail(request, r_id):
|
||||
repository = Repository.objects.filter(pk=r_id).first()
|
||||
if not repository:
|
||||
|
|
|
@ -10,16 +10,18 @@ from apps.schedule.models import Task, History
|
|||
from apps.schedule.executors import local_executor, host_executor
|
||||
from apps.host.models import Host
|
||||
from django.conf import settings
|
||||
from libs import json_response, JsonParser, Argument, human_datetime
|
||||
from libs import json_response, JsonParser, Argument, human_datetime, auth
|
||||
import json
|
||||
|
||||
|
||||
class Schedule(View):
|
||||
@auth('schedule.schedule.view')
|
||||
def get(self, request):
|
||||
tasks = Task.objects.all()
|
||||
types = [x['type'] for x in tasks.order_by('type').values('type').distinct()]
|
||||
return json_response({'types': types, 'tasks': [x.to_dict() for x in tasks]})
|
||||
|
||||
@auth('schedule.schedule.add|schedule.schedule.edit')
|
||||
def post(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, required=False),
|
||||
|
@ -61,6 +63,7 @@ class Schedule(View):
|
|||
Task.objects.create(created_by=request.user, **form)
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('schedule.schedule.edit')
|
||||
def patch(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象'),
|
||||
|
@ -81,6 +84,7 @@ class Schedule(View):
|
|||
task.save()
|
||||
return json_response(error=error)
|
||||
|
||||
@auth('schedule.schedule.del')
|
||||
def delete(self, request):
|
||||
form, error = JsonParser(
|
||||
Argument('id', type=int, help='请指定操作对象')
|
||||
|
@ -96,6 +100,7 @@ class Schedule(View):
|
|||
|
||||
|
||||
class HistoryView(View):
|
||||
@auth('schedule.schedule.view')
|
||||
def get(self, request, t_id):
|
||||
task = Task.objects.filter(pk=t_id).first()
|
||||
if not task:
|
||||
|
@ -108,6 +113,7 @@ class HistoryView(View):
|
|||
histories = History.objects.filter(task_id=t_id)
|
||||
return json_response([x.to_list() for x in histories])
|
||||
|
||||
@auth('schedule.schedule.edit')
|
||||
def post(self, request, t_id):
|
||||
task = Task.objects.filter(pk=t_id).first()
|
||||
if not task:
|
||||
|
@ -156,6 +162,7 @@ class HistoryView(View):
|
|||
return data
|
||||
|
||||
|
||||
@auth('schedule.schedule.add|schedule.schedule.edit')
|
||||
def next_run_time(request):
|
||||
form, error = JsonParser(
|
||||
Argument('rule', help='参数错误'),
|
||||
|
|
|
@ -3,19 +3,19 @@
|
|||
# Released under the AGPL-3.0 License.
|
||||
import django
|
||||
from django.core.cache import cache
|
||||
from django.views.generic import View
|
||||
from django.conf import settings
|
||||
from libs import JsonParser, Argument, json_response
|
||||
from libs import JsonParser, Argument, json_response, auth
|
||||
from libs.utils import generate_random_str
|
||||
from libs.mail import Mail
|
||||
from libs.spug import send_login_wx_code
|
||||
from libs.mixins import AdminView
|
||||
from apps.setting.utils import AppSetting
|
||||
from apps.setting.models import Setting
|
||||
import platform
|
||||
import ldap
|
||||
|
||||
|
||||
class SettingView(View):
|
||||
class SettingView(AdminView):
|
||||
def get(self, request):
|
||||
data = Setting.objects.all()
|
||||
return json_response([x.to_view() for x in data])
|
||||
|
@ -30,7 +30,7 @@ class SettingView(View):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
class MFAView(View):
|
||||
class MFAView(AdminView):
|
||||
def get(self, request):
|
||||
if not request.user.wx_token:
|
||||
return json_response(error='检测到当前账户未配置微信Token,请配置后再尝试启用MFA认证,否则可能造成系统无法正常登录。')
|
||||
|
@ -61,6 +61,7 @@ class MFAView(View):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('admin')
|
||||
def ldap_test(request):
|
||||
form, error = JsonParser(
|
||||
Argument('server'),
|
||||
|
@ -79,6 +80,7 @@ def ldap_test(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('admin')
|
||||
def email_test(request):
|
||||
form, error = JsonParser(
|
||||
Argument('server', help='请输入邮件服务地址'),
|
||||
|
@ -97,6 +99,7 @@ def email_test(request):
|
|||
return json_response(error=error)
|
||||
|
||||
|
||||
@auth('admin')
|
||||
def mfa_test(request):
|
||||
if not request.user.wx_token:
|
||||
return json_response(error='检测到当前账户未配置微信Token,请配置后再尝试启用MFA认证,否则可能造成系统无法正常登录。')
|
||||
|
@ -106,6 +109,7 @@ def mfa_test(request):
|
|||
return json_response()
|
||||
|
||||
|
||||
@auth('admin')
|
||||
def get_about(request):
|
||||
return json_response({
|
||||
'python_version': platform.python_version(),
|
||||
|
|
|
@ -5,35 +5,20 @@ from functools import wraps
|
|||
from .utils import json_response
|
||||
|
||||
|
||||
def permission_required_supper(view_func):
|
||||
@wraps(view_func)
|
||||
def wrapper(*args, **kwargs):
|
||||
request = None
|
||||
for item in args:
|
||||
if hasattr(item, 'user'):
|
||||
request = item
|
||||
break
|
||||
if request is None or not request.user.is_supper:
|
||||
return json_response(error='需要管理员权限')
|
||||
return view_func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def permission_required(perm_list):
|
||||
def auth(perm_list):
|
||||
def decorate(view_func):
|
||||
codes = (perm_list,) if isinstance(perm_list, str) else perm_list
|
||||
codes = perm_list.split('|')
|
||||
|
||||
@wraps(view_func)
|
||||
def wrapper(*args, **kwargs):
|
||||
request = None
|
||||
for item in args:
|
||||
user = None
|
||||
for item in args[:2]:
|
||||
if hasattr(item, 'user'):
|
||||
request = item
|
||||
user = item.user
|
||||
break
|
||||
if request is None or (not request.user.is_supper and not request.user.has_perms(codes)):
|
||||
return json_response(error='拒绝访问')
|
||||
if user and user.has_perms(codes):
|
||||
return view_func(*args, **kwargs)
|
||||
return json_response(error='权限拒绝')
|
||||
|
||||
return wrapper
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Copyright: (c) OpenSpug Organization. https://github.com/openspug/spug
|
||||
# Copyright: (c) <spug.dev@gmail.com>
|
||||
# Released under the AGPL-3.0 License.
|
||||
from django.views.generic import View
|
||||
from .utils import json_response
|
||||
|
||||
|
||||
|
@ -24,38 +25,9 @@ class ModelMixin(object):
|
|||
self.save()
|
||||
|
||||
|
||||
# 使用该混入类,需要request.user对象实现has_perms方法
|
||||
class PermissionMixin(object):
|
||||
"""
|
||||
CBV mixin which verifies that the current user has all specified
|
||||
permissions.
|
||||
"""
|
||||
permission_required = None
|
||||
|
||||
def get_permission_required(self):
|
||||
"""
|
||||
Override this method to override the permission_required attribute.
|
||||
Must return an iterable.
|
||||
"""
|
||||
if self.permission_required is None:
|
||||
raise AttributeError(
|
||||
'{0} is missing the permission_required attribute. Define {0}.permission_required, or override '
|
||||
'{0}.get_permission_required().'.format(self.__class__.__name__)
|
||||
)
|
||||
if isinstance(self.permission_required, str):
|
||||
perms = (self.permission_required,)
|
||||
else:
|
||||
perms = self.permission_required
|
||||
return perms
|
||||
|
||||
def has_permission(self):
|
||||
"""
|
||||
Override this method to customize the way permissions are checked.
|
||||
"""
|
||||
perms = self.get_permission_required()
|
||||
return self.request.user.has_perms(perms)
|
||||
|
||||
class AdminView(View):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not self.has_permission():
|
||||
return json_response(error='拒绝访问')
|
||||
return super(PermissionMixin, self).dispatch(request, *args, **kwargs)
|
||||
if hasattr(request, 'user') and request.user.is_supper:
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
else:
|
||||
return json_response(error='权限拒绝')
|
||||
|
|
|
@ -3,15 +3,22 @@
|
|||
* Copyright (c) <spug.dev@gmail.com>
|
||||
* Released under the AGPL-3.0 License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import React, {useEffect} from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Modal, Steps } from 'antd';
|
||||
import Step1 from './Step1';
|
||||
import Step2 from './Step2';
|
||||
import store from './store';
|
||||
import styles from './index.module.css';
|
||||
import groupStore from '../alarm/group/store';
|
||||
|
||||
export default observer(function () {
|
||||
useEffect(() => {
|
||||
if (groupStore.records.length === 0) {
|
||||
groupStore.fetchRecords();
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible
|
||||
|
|
|
@ -9,36 +9,13 @@ import { Table, Modal, Radio, Tag, message } from 'antd';
|
|||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { Action, AuthButton, TableCard } from 'components';
|
||||
import { http, hasPermission } from 'libs';
|
||||
import groupStore from '../alarm/group/store';
|
||||
import hostStore from '../host/store';
|
||||
import store from './store';
|
||||
|
||||
@observer
|
||||
class ComTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
hosts: {}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
store.fetchRecords();
|
||||
if (groupStore.records.length === 0) groupStore.fetchRecords();
|
||||
if (!hostStore.records || hostStore.records.length === 0) {
|
||||
hostStore.fetchRecords().then(this._handleHosts)
|
||||
} else {
|
||||
this._handleHosts()
|
||||
}
|
||||
}
|
||||
|
||||
_handleHosts = () => {
|
||||
const tmp = {};
|
||||
for (let item of hostStore.records) {
|
||||
tmp[item.id] = item
|
||||
}
|
||||
this.setState({hosts: tmp})
|
||||
};
|
||||
|
||||
handleActive = (text) => {
|
||||
Modal.confirm({
|
||||
|
|
|
@ -22,7 +22,7 @@ class ComTable extends React.Component {
|
|||
moreMenus = (info) => (
|
||||
<Menu>
|
||||
<Menu.Item>
|
||||
<LinkButton onClick={() => this.handleTest(info)}>执行测试</LinkButton>
|
||||
<LinkButton auth="schedule.schedule.edit" onClick={() => this.handleTest(info)}>执行测试</LinkButton>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<LinkButton
|
||||
|
|
Loading…
Reference in New Issue