views.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. # Copyright: (c) OpenSpug Organization. https://github.com/openspug/spug
  2. # Copyright: (c) <spug.dev@gmail.com>
  3. # Released under the AGPL-3.0 License.
  4. from django.views.generic import View
  5. from django.db.models import F
  6. from libs import JsonParser, Argument, json_response
  7. from apps.app.models import App, Deploy, DeployExtend1, DeployExtend2
  8. from apps.config.models import Config
  9. from apps.app.utils import fetch_versions, remove_repo
  10. from apps.setting.utils import AppSetting
  11. import json
  12. import re
  13. class AppView(View):
  14. def get(self, request):
  15. query = {}
  16. if not request.user.is_supper:
  17. query['id__in'] = request.user.deploy_perms['apps']
  18. apps = App.objects.filter(**query)
  19. return json_response(apps)
  20. def post(self, request):
  21. form, error = JsonParser(
  22. Argument('id', type=int, required=False),
  23. Argument('name', help='请输入服务名称'),
  24. Argument('key', help='请输入唯一标识符'),
  25. Argument('desc', required=False)
  26. ).parse(request.body)
  27. if error is None:
  28. if not re.fullmatch(r'[-\w]+', form.key, re.ASCII):
  29. return json_response(error='标识符必须为字母、数字、-和下划线的组合')
  30. app = App.objects.filter(key=form.key).first()
  31. if app and app.id != form.id:
  32. return json_response(error=f'唯一标识符 {form.key} 已存在,请更改后重试')
  33. if form.id:
  34. App.objects.filter(pk=form.id).update(**form)
  35. else:
  36. app = App.objects.create(created_by=request.user, **form)
  37. app.sort_id = app.id
  38. app.save()
  39. return json_response(error=error)
  40. def patch(self, request):
  41. form, error = JsonParser(
  42. Argument('id', type=int, help='参数错误'),
  43. Argument('rel_apps', type=list, required=False),
  44. Argument('rel_services', type=list, required=False),
  45. Argument('sort', filter=lambda x: x in ('up', 'down'), required=False)
  46. ).parse(request.body)
  47. if error is None:
  48. app = App.objects.filter(pk=form.id).first()
  49. if not app:
  50. return json_response(error='未找到指定应用')
  51. if form.rel_apps is not None:
  52. app.rel_apps = json.dumps(form.rel_apps)
  53. if form.rel_services is not None:
  54. app.rel_services = json.dumps(form.rel_services)
  55. if form.sort:
  56. if form.sort == 'up':
  57. tmp = App.objects.filter(sort_id__gt=app.sort_id).last()
  58. else:
  59. tmp = App.objects.filter(sort_id__lt=app.sort_id).first()
  60. if tmp:
  61. tmp.sort_id, app.sort_id = app.sort_id, tmp.sort_id
  62. tmp.save()
  63. app.save()
  64. return json_response(error=error)
  65. def delete(self, request):
  66. form, error = JsonParser(
  67. Argument('id', type=int, help='请指定操作对象')
  68. ).parse(request.GET)
  69. if error is None:
  70. if Deploy.objects.filter(app_id=form.id).exists():
  71. return json_response(error='该应用在应用发布中已存在关联的发布配置,请删除相关发布配置后再尝试删除')
  72. if Config.objects.filter(type='app', o_id=form.id).exists():
  73. return json_response(error='该应用在配置中心已存在关联的配置信息,请删除相关配置后再尝试删除')
  74. App.objects.filter(pk=form.id).delete()
  75. return json_response(error=error)
  76. class DeployView(View):
  77. def get(self, request):
  78. form, error = JsonParser(
  79. Argument('app_id', type=int, required=False)
  80. ).parse(request.GET, True)
  81. if not request.user.is_supper:
  82. perms = request.user.deploy_perms
  83. form.app_id__in = perms['apps']
  84. form.env_id__in = perms['envs']
  85. deploys = Deploy.objects.filter(**form) \
  86. .annotate(app_name=F('app__name'), app_key=F('app__key')) \
  87. .order_by('-app__sort_id')
  88. return json_response(deploys)
  89. def post(self, request):
  90. form, error = JsonParser(
  91. Argument('id', type=int, required=False),
  92. Argument('app_id', type=int, help='请选择应用'),
  93. Argument('env_id', type=int, help='请选择环境'),
  94. Argument('host_ids', type=list, filter=lambda x: len(x), help='请选择要部署的主机'),
  95. Argument('rst_notify', type=dict, help='请选择发布结果通知方式'),
  96. Argument('extend', filter=lambda x: x in dict(Deploy.EXTENDS), help='请选择发布类型'),
  97. Argument('is_parallel', type=bool, default=True),
  98. Argument('is_audit', type=bool, default=False)
  99. ).parse(request.body)
  100. if error is None:
  101. deploy = Deploy.objects.filter(app_id=form.app_id, env_id=form.env_id).first()
  102. if deploy and deploy.id != form.id:
  103. return json_response(error='应用在该环境下已经存在发布配置')
  104. form.host_ids = json.dumps(form.host_ids)
  105. form.rst_notify = json.dumps(form.rst_notify)
  106. if form.extend == '1':
  107. extend_form, error = JsonParser(
  108. Argument('git_repo', handler=str.strip, help='请输入git仓库地址'),
  109. Argument('dst_dir', handler=str.strip, help='请输入发布部署路径'),
  110. Argument('dst_repo', handler=str.strip, help='请输入发布存储路径'),
  111. Argument('versions', type=int, filter=lambda x: x > 0, help='请输入发布保留版本数量'),
  112. Argument('filter_rule', type=dict, help='参数错误'),
  113. Argument('hook_pre_server', handler=str.strip, default=''),
  114. Argument('hook_post_server', handler=str.strip, default=''),
  115. Argument('hook_pre_host', handler=str.strip, default=''),
  116. Argument('hook_post_host', handler=str.strip, default='')
  117. ).parse(request.body)
  118. if error:
  119. return json_response(error=error)
  120. extend_form.dst_dir = extend_form.dst_dir.rstrip('/')
  121. extend_form.filter_rule = json.dumps(extend_form.filter_rule)
  122. if form.id:
  123. extend = DeployExtend1.objects.filter(deploy_id=form.id).first()
  124. if extend.git_repo != extend_form.git_repo:
  125. remove_repo(form.id)
  126. Deploy.objects.filter(pk=form.id).update(**form)
  127. DeployExtend1.objects.filter(deploy_id=form.id).update(**extend_form)
  128. else:
  129. deploy = Deploy.objects.create(created_by=request.user, **form)
  130. DeployExtend1.objects.create(deploy=deploy, **extend_form)
  131. elif form.extend == '2':
  132. extend_form, error = JsonParser(
  133. Argument('server_actions', type=list, help='请输入执行动作'),
  134. Argument('host_actions', type=list, help='请输入执行动作')
  135. ).parse(request.body)
  136. if error:
  137. return json_response(error=error)
  138. if len(extend_form.server_actions) + len(extend_form.host_actions) == 0:
  139. return json_response(error='请至少设置一个执行的动作')
  140. extend_form.require_upload = any(x.get('src_mode') == '1' for x in extend_form.host_actions)
  141. extend_form.server_actions = json.dumps(extend_form.server_actions)
  142. extend_form.host_actions = json.dumps(extend_form.host_actions)
  143. if form.id:
  144. Deploy.objects.filter(pk=form.id).update(**form)
  145. DeployExtend2.objects.filter(deploy_id=form.id).update(**extend_form)
  146. else:
  147. deploy = Deploy.objects.create(created_by=request.user, **form)
  148. DeployExtend2.objects.create(deploy=deploy, **extend_form)
  149. return json_response(error=error)
  150. def delete(self, request):
  151. form, error = JsonParser(
  152. Argument('id', type=int, help='请指定操作对象')
  153. ).parse(request.GET)
  154. if error is None:
  155. deploy = Deploy.objects.get(pk=form.id)
  156. if deploy.deployrequest_set.exists():
  157. return json_response(error='已存在关联的发布记录,请删除关联的发布记录后再尝试删除发布配置')
  158. for item in deploy.repository_set.all():
  159. item.delete()
  160. deploy.delete()
  161. return json_response(error=error)
  162. def get_versions(request, d_id):
  163. deploy = Deploy.objects.filter(pk=d_id).first()
  164. if not deploy:
  165. return json_response(error='未找到指定应用')
  166. if deploy.extend == '2':
  167. return json_response(error='该应用不支持此操作')
  168. branches, tags = fetch_versions(deploy)
  169. return json_response({'branches': branches, 'tags': tags})
  170. def kit_key(request):
  171. api_key = AppSetting.get_default('api_key')
  172. return json_response(api_key)